Compare commits

...

21 Commits

Author SHA1 Message Date
e877045671 feat: fix CAS login crash bug (#1549) 2023-02-14 16:52:15 +08:00
29f1ec08a2 fix: fix CI error by auto waiting for localhost:7001 to start up (#1548) 2023-02-14 14:50:58 +08:00
389744a27d feat: change claims to claimsWithoutThirdIdp when gen token (#1552) 2023-02-14 09:33:46 +08:00
dc7b66822d feat: change token ExpiresIn to second (#1550) 2023-02-14 09:18:30 +08:00
efacf8226c fix: session Id error (#1554) 2023-02-13 22:58:26 +08:00
6beb68dcce fix: some bugs in session module when testing single-log-in (#1547)
Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>
2023-02-13 18:16:31 +08:00
c9b990a319 Add removeExtraSessionIds() 2023-02-12 21:11:16 +08:00
eedcde3aa5 Refactor session.go 2023-02-12 21:06:08 +08:00
950a274b23 fix: region don't display in userEditPage (#1544) 2023-02-12 18:56:56 +08:00
478bd05db4 Improve error handling in migrator 2023-02-12 10:39:20 +08:00
9256791420 feat: app session control and db migrate (#1539)
* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process (#1533)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

---------

Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>

* fix: migrate err

* fix: migrate err

* feat: app session control and db migrate

* feat: app session control and db migrate

* feat: app session control and db migrate

---------

Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>
2023-02-12 09:33:24 +08:00
6f2ef32d02 Update xorm.io/core to v0.7.3 2023-02-11 17:46:34 +08:00
8b8c866fd2 feat: replace gomail and disable the Email username check for Mailtrap (#1538) 2023-02-11 15:59:23 +08:00
6f7230e949 feat: support refresh token on GetOAuthToken (#1536) 2023-02-10 23:52:13 +08:00
wht
9558bb4167 feat: fix file name length problem (#1534) 2023-02-10 20:27:20 +08:00
04567babf8 feat: fix click MenuItem blank part invalid bug (#1535) 2023-02-10 18:11:15 +08:00
543b316942 feat: update swagger parameter id description (#1532) 2023-02-10 10:42:16 +08:00
e2b6e8ee6e chore: unify migrate database way (#1530) 2023-02-09 19:28:15 +08:00
wht
e7e0518517 feat: fix the upload file name contains space problem (#1527) 2023-02-07 23:26:17 +08:00
943aa61869 feat: add provider icons and menus (#1522)
* fix: add provider icons(email and captcha) and menus

* fix: add provider icons and menus
2023-02-06 20:28:40 +08:00
wht
fcc75dd3be feat: fix the Unicode filename encoding bug in storage provider (#1518) 2023-02-04 18:09:18 +08:00
79 changed files with 1170 additions and 417 deletions

View File

@ -97,21 +97,20 @@ jobs:
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: 16 node-version: 16
- name: back start
run: nohup go run ./main.go &
working-directory: ./
- name: front install - name: front install
run: yarn install run: yarn install
working-directory: ./web working-directory: ./web
- name: front start - name: front start
run: nohup yarn start & run: nohup yarn start &
working-directory: ./web working-directory: ./web
- name: back start - uses: cypress-io/github-action@v4
run: nohup go run ./main.go & with:
working-directory: ./ working-directory: ./web
- name: Sleep for starting wait-on: 'http://localhost:7001'
run: sleep 90s wait-on-timeout: 180
shell: bash
- name: e2e
run: npx cypress run --spec "**/e2e/**.cy.js"
working-directory: ./web
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: failure() if: failure()

View File

@ -20,9 +20,9 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
xormadapter "github.com/casdoor/xorm-adapter/v3"
stringadapter "github.com/qiangmzsx/string-adapter/v2" stringadapter "github.com/qiangmzsx/string-adapter/v2"
) )

View File

@ -254,7 +254,10 @@ func (c *ApiController) Logout() {
if accessToken == "" && redirectUri == "" { if accessToken == "" && redirectUri == "" {
c.ClearUserSession() c.ClearUserSession()
object.DeleteSessionId(user, c.Ctx.Input.CruSession.SessionID()) // TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
owner, username := util.GetOwnerAndNameFromId(user)
object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)
application := c.GetSessionApplication() application := c.GetSessionApplication()
@ -291,7 +294,8 @@ func (c *ApiController) Logout() {
} }
c.ClearUserSession() c.ClearUserSession()
object.DeleteSessionId(user, c.Ctx.Input.CruSession.SessionID()) // TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
object.DeleteSessionId(util.GetSessionId(object.CasdoorOrganization, object.CasdoorApplication, user), c.Ctx.Input.CruSession.SessionID())
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)
c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state)) c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state))

View File

@ -63,7 +63,7 @@ func (c *ApiController) GetApplications() {
// @Title GetApplication // @Title GetApplication
// @Tag Application API // @Tag Application API
// @Description get the detail of an application // @Description get the detail of an application
// @Param id query string true "The id of the application." // @Param id query string true "The id ( owner/name ) of the application."
// @Success 200 {object} object.Application The Response object // @Success 200 {object} object.Application The Response object
// @router /get-application [get] // @router /get-application [get]
func (c *ApiController) GetApplication() { func (c *ApiController) GetApplication() {
@ -78,7 +78,7 @@ func (c *ApiController) GetApplication() {
// @Title GetUserApplication // @Title GetUserApplication
// @Tag Application API // @Tag Application API
// @Description get the detail of the user's application // @Description get the detail of the user's application
// @Param id query string true "The id of the user" // @Param id query string true "The id ( owner/name ) of the user"
// @Success 200 {object} object.Application The Response object // @Success 200 {object} object.Application The Response object
// @router /get-user-application [get] // @router /get-user-application [get]
func (c *ApiController) GetUserApplication() { func (c *ApiController) GetUserApplication() {
@ -134,7 +134,7 @@ func (c *ApiController) GetOrganizationApplications() {
// @Title UpdateApplication // @Title UpdateApplication
// @Tag Application API // @Tag Application API
// @Description update an application // @Description update an application
// @Param id query string true "The id of the application" // @Param id query string true "The id ( owner/name ) of the application"
// @Param body body object.Application true "The details of the application" // @Param body body object.Application true "The details of the application"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-application [post] // @router /update-application [post]

View File

@ -139,8 +139,13 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}) })
} }
if resp.Status == "ok" { if resp.Status == "ok" && user.Owner == object.CasdoorOrganization && application.Name == object.CasdoorApplication {
object.SetSession(user.GetId(), c.Ctx.Input.CruSession.SessionID()) object.AddSession(&object.Session{
Owner: user.Owner,
Name: user.Name,
Application: application.Name,
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
})
} }
return resp return resp

View File

@ -18,9 +18,9 @@ import (
"encoding/json" "encoding/json"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
xormadapter "github.com/casbin/xorm-adapter/v3"
"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"
) )
func (c *ApiController) GetCasbinAdapters() { func (c *ApiController) GetCasbinAdapters() {

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetCerts() {
// @Title GetCert // @Title GetCert
// @Tag Cert API // @Tag Cert API
// @Description get cert // @Description get cert
// @Param id query string true "The id of the cert" // @Param id query string true "The id ( owner/name ) of the cert"
// @Success 200 {object} object.Cert The Response object // @Success 200 {object} object.Cert The Response object
// @router /get-cert [get] // @router /get-cert [get]
func (c *ApiController) GetCert() { func (c *ApiController) GetCert() {
@ -66,7 +66,7 @@ func (c *ApiController) GetCert() {
// @Title UpdateCert // @Title UpdateCert
// @Tag Cert API // @Tag Cert API
// @Description update cert // @Description update cert
// @Param id query string true "The id of the cert" // @Param id query string true "The id ( owner/name ) of the cert"
// @Param body body object.Cert true "The details of the cert" // @Param body body object.Cert true "The details of the cert"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-cert [post] // @router /update-cert [post]

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetModels() {
// @Title GetModel // @Title GetModel
// @Tag Model API // @Tag Model API
// @Description get model // @Description get model
// @Param id query string true "The id of the model" // @Param id query string true "The id ( owner/name ) of the model"
// @Success 200 {object} object.Model The Response object // @Success 200 {object} object.Model The Response object
// @router /get-model [get] // @router /get-model [get]
func (c *ApiController) GetModel() { func (c *ApiController) GetModel() {
@ -66,7 +66,7 @@ func (c *ApiController) GetModel() {
// @Title UpdateModel // @Title UpdateModel
// @Tag Model API // @Tag Model API
// @Description update model // @Description update model
// @Param id query string true "The id of the model" // @Param id query string true "The id ( owner/name ) of the model"
// @Param body body object.Model true "The details of the model" // @Param body body object.Model true "The details of the model"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-model [post] // @router /update-model [post]

View File

@ -66,7 +66,7 @@ func (c *ApiController) GetOrganization() {
// @Title UpdateOrganization // @Title UpdateOrganization
// @Tag Organization API // @Tag Organization API
// @Description update organization // @Description update organization
// @Param id query string true "The id of the organization" // @Param id query string true "The id ( owner/name ) of the organization"
// @Param body body object.Organization true "The details of the organization" // @Param body body object.Organization true "The details of the organization"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-organization [post] // @router /update-organization [post]

View File

@ -71,7 +71,7 @@ func (c *ApiController) GetUserPayments() {
// @Title GetPayment // @Title GetPayment
// @Tag Payment API // @Tag Payment API
// @Description get payment // @Description get payment
// @Param id query string true "The id of the payment" // @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} object.Payment The Response object // @Success 200 {object} object.Payment The Response object
// @router /get-payment [get] // @router /get-payment [get]
func (c *ApiController) GetPayment() { func (c *ApiController) GetPayment() {
@ -85,7 +85,7 @@ func (c *ApiController) GetPayment() {
// @Title UpdatePayment // @Title UpdatePayment
// @Tag Payment API // @Tag Payment API
// @Description update payment // @Description update payment
// @Param id query string true "The id of the payment" // @Param id query string true "The id ( owner/name ) of the payment"
// @Param body body object.Payment true "The details of the payment" // @Param body body object.Payment true "The details of the payment"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-payment [post] // @router /update-payment [post]
@ -172,7 +172,7 @@ func (c *ApiController) NotifyPayment() {
// @Title InvoicePayment // @Title InvoicePayment
// @Tag Payment API // @Tag Payment API
// @Description invoice payment // @Description invoice payment
// @Param id query string true "The id of the payment" // @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /invoice-payment [post] // @router /invoice-payment [post]
func (c *ApiController) InvoicePayment() { func (c *ApiController) InvoicePayment() {

View File

@ -69,7 +69,7 @@ func (c *ApiController) GetPermissionsBySubmitter() {
// @Title GetPermissionsByRole // @Title GetPermissionsByRole
// @Tag Permission API // @Tag Permission API
// @Description get permissions by role // @Description get permissions by role
// @Param id query string true "The id of the role" // @Param id query string true "The id ( owner/name ) of the role"
// @Success 200 {array} object.Permission The Response object // @Success 200 {array} object.Permission The Response object
// @router /get-permissions-by-role [get] // @router /get-permissions-by-role [get]
func (c *ApiController) GetPermissionsByRole() { func (c *ApiController) GetPermissionsByRole() {
@ -83,7 +83,7 @@ func (c *ApiController) GetPermissionsByRole() {
// @Title GetPermission // @Title GetPermission
// @Tag Permission API // @Tag Permission API
// @Description get permission // @Description get permission
// @Param id query string true "The id of the permission" // @Param id query string true "The id ( owner/name ) of the permission"
// @Success 200 {object} object.Permission The Response object // @Success 200 {object} object.Permission The Response object
// @router /get-permission [get] // @router /get-permission [get]
func (c *ApiController) GetPermission() { func (c *ApiController) GetPermission() {
@ -97,7 +97,7 @@ func (c *ApiController) GetPermission() {
// @Title UpdatePermission // @Title UpdatePermission
// @Tag Permission API // @Tag Permission API
// @Description update permission // @Description update permission
// @Param id query string true "The id of the permission" // @Param id query string true "The id ( owner/name ) of the permission"
// @Param body body object.Permission true "The details of the permission" // @Param body body object.Permission true "The details of the permission"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-permission [post] // @router /update-permission [post]

View File

@ -53,7 +53,7 @@ func (c *ApiController) GetProducts() {
// @Title GetProduct // @Title GetProduct
// @Tag Product API // @Tag Product API
// @Description get product // @Description get product
// @Param id query string true "The id of the product" // @Param id query string true "The id ( owner/name ) of the product"
// @Success 200 {object} object.Product The Response object // @Success 200 {object} object.Product The Response object
// @router /get-product [get] // @router /get-product [get]
func (c *ApiController) GetProduct() { func (c *ApiController) GetProduct() {
@ -70,7 +70,7 @@ func (c *ApiController) GetProduct() {
// @Title UpdateProduct // @Title UpdateProduct
// @Tag Product API // @Tag Product API
// @Description update product // @Description update product
// @Param id query string true "The id of the product" // @Param id query string true "The id ( owner/name ) of the product"
// @Param body body object.Product true "The details of the product" // @Param body body object.Product true "The details of the product"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-product [post] // @router /update-product [post]
@ -130,7 +130,7 @@ func (c *ApiController) DeleteProduct() {
// @Title BuyProduct // @Title BuyProduct
// @Tag Product API // @Tag Product API
// @Description buy product // @Description buy product
// @Param id query string true "The id of the product" // @Param id query string true "The id ( owner/name ) of the product"
// @Param providerName query string true "The name of the provider" // @Param providerName query string true "The name of the provider"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /buy-product [post] // @router /buy-product [post]

View File

@ -76,7 +76,7 @@ func (c *ApiController) GetGlobalProviders() {
// @Title GetProvider // @Title GetProvider
// @Tag Provider API // @Tag Provider API
// @Description get provider // @Description get provider
// @Param id query string true "The id of the provider" // @Param id query string true "The id ( owner/name ) of the provider"
// @Success 200 {object} object.Provider The Response object // @Success 200 {object} object.Provider The Response object
// @router /get-provider [get] // @router /get-provider [get]
func (c *ApiController) GetProvider() { func (c *ApiController) GetProvider() {
@ -89,7 +89,7 @@ func (c *ApiController) GetProvider() {
// @Title UpdateProvider // @Title UpdateProvider
// @Tag Provider API // @Tag Provider API
// @Description update provider // @Description update provider
// @Param id query string true "The id of the provider" // @Param id query string true "The id ( owner/name ) of the provider"
// @Param body body object.Provider true "The details of the provider" // @Param body body object.Provider true "The details of the provider"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-provider [post] // @router /update-provider [post]

View File

@ -180,6 +180,7 @@ func (c *ApiController) UploadResource() {
fileType, _ = util.GetOwnerAndNameFromId(mimeType) fileType, _ = util.GetOwnerAndNameFromId(mimeType)
} }
fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 175)
if tag != "avatar" && tag != "termsOfUse" { if tag != "avatar" && tag != "termsOfUse" {
ext := filepath.Ext(filepath.Base(fullFilePath)) ext := filepath.Ext(filepath.Base(fullFilePath))
index := len(fullFilePath) - len(ext) index := len(fullFilePath) - len(ext)

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetRoles() {
// @Title GetRole // @Title GetRole
// @Tag Role API // @Tag Role API
// @Description get role // @Description get role
// @Param id query string true "The id of the role" // @Param id query string true "The id ( owner/name ) of the role"
// @Success 200 {object} object.Role The Response object // @Success 200 {object} object.Role The Response object
// @router /get-role [get] // @router /get-role [get]
func (c *ApiController) GetRole() { func (c *ApiController) GetRole() {
@ -66,7 +66,7 @@ func (c *ApiController) GetRole() {
// @Title UpdateRole // @Title UpdateRole
// @Tag Role API // @Tag Role API
// @Description update role // @Description update role
// @Param id query string true "The id of the role" // @Param id query string true "The id ( owner/name ) of the role"
// @Param body body object.Role true "The details of the role" // @Param body body object.Role true "The details of the role"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-role [post] // @router /update-role [post]

View File

@ -22,29 +22,10 @@ import (
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
// DeleteSession
// @Title DeleteSession
// @Tag Session API
// @Description Delete session by userId
// @Param ID query string true "The ID(owner/name) of user."
// @Success 200 {array} string The Response object
// @router /delete-session [post]
func (c *ApiController) DeleteSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetId(session.Owner, session.Name)))
c.ServeJSON()
}
// GetSessions // GetSessions
// @Title GetSessions // @Title GetSessions
// @Tag Session API // @Tag Session API
// @Description Get organization user sessions // @Description Get organization user sessions.
// @Param owner query string true "The organization name" // @Param owner query string true "The organization name"
// @Success 200 {array} string The Response object // @Success 200 {array} string The Response object
// @router /get-sessions [get] // @router /get-sessions [get]
@ -66,3 +47,93 @@ func (c *ApiController) GetSessions() {
c.ResponseOk(sessions, paginator.Nums()) c.ResponseOk(sessions, paginator.Nums())
} }
} }
// GetSingleSession
// @Title GetSingleSession
// @Tag Session API
// @Description Get session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /get-session [get]
func (c *ApiController) GetSingleSession() {
id := c.Input().Get("sessionPkId")
c.Data["json"] = object.GetSingleSession(id)
c.ServeJSON()
}
// UpdateSession
// @Title UpdateSession
// @Tag Session API
// @Description Update session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /update-session [post]
func (c *ApiController) UpdateSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateSession(util.GetSessionId(session.Owner, session.Name, session.Application), &session))
c.ServeJSON()
}
// AddSession
// @Title AddSession
// @Tag Session API
// @Description Add session for one user in one application. If there are other existing sessions, join the session into the list.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be added"
// @Success 200 {array} string The Response object
// @router /add-session [post]
func (c *ApiController) AddSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddSession(&session))
c.ServeJSON()
}
// DeleteSession
// @Title DeleteSession
// @Tag Session API
// @Description Delete session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /delete-session [post]
func (c *ApiController) DeleteSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application)))
c.ServeJSON()
}
// IsSessionDuplicated
// @Title IsSessionDuplicated
// @Tag Session API
// @Description Check if there are other different sessions for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be checked"
// @Success 200 {array} string The Response object
// @router /is-session-duplicated [get]
func (c *ApiController) IsSessionDuplicated() {
id := c.Input().Get("sessionPkId")
sessionId := c.Input().Get("sessionId")
isUserSessionDuplicated := object.IsSessionDuplicated(id, sessionId)
c.Data["json"] = &Response{Status: "ok", Msg: "", Data: isUserSessionDuplicated}
c.ServeJSON()
}

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetSyncers() {
// @Title GetSyncer // @Title GetSyncer
// @Tag Syncer API // @Tag Syncer API
// @Description get syncer // @Description get syncer
// @Param id query string true "The id of the syncer" // @Param id query string true "The id ( owner/name ) of the syncer"
// @Success 200 {object} object.Syncer The Response object // @Success 200 {object} object.Syncer The Response object
// @router /get-syncer [get] // @router /get-syncer [get]
func (c *ApiController) GetSyncer() { func (c *ApiController) GetSyncer() {
@ -66,7 +66,7 @@ func (c *ApiController) GetSyncer() {
// @Title UpdateSyncer // @Title UpdateSyncer
// @Tag Syncer API // @Tag Syncer API
// @Description update syncer // @Description update syncer
// @Param id query string true "The id of the syncer" // @Param id query string true "The id ( owner/name ) of the syncer"
// @Param body body object.Syncer true "The details of the syncer" // @Param body body object.Syncer true "The details of the syncer"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-syncer [post] // @router /update-syncer [post]

View File

@ -29,7 +29,7 @@ type SystemInfo struct {
// @Title GetSystemInfo // @Title GetSystemInfo
// @Tag System API // @Tag System API
// @Description get user's system info // @Description get user's system info
// @Param id query string true "The id of the user" // @Param id query string true "The id ( owner/name ) of the user"
// @Success 200 {object} object.SystemInfo The Response object // @Success 200 {object} object.SystemInfo The Response object
// @router /get-system-info [get] // @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() { func (c *ApiController) GetSystemInfo() {

View File

@ -54,7 +54,7 @@ func (c *ApiController) GetTokens() {
// @Title GetToken // @Title GetToken
// @Tag Token API // @Tag Token API
// @Description get token // @Description get token
// @Param id query string true "The id of token" // @Param id query string true "The id ( owner/name ) of token"
// @Success 200 {object} object.Token The Response object // @Success 200 {object} object.Token The Response object
// @router /get-token [get] // @router /get-token [get]
func (c *ApiController) GetToken() { func (c *ApiController) GetToken() {
@ -68,7 +68,7 @@ func (c *ApiController) GetToken() {
// @Title UpdateToken // @Title UpdateToken
// @Tag Token API // @Tag Token API
// @Description update token // @Description update token
// @Param id query string true "The id of token" // @Param id query string true "The id ( owner/name ) of token"
// @Param body body object.Token true "Details of the token" // @Param body body object.Token true "Details of the token"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-token [post] // @router /update-token [post]
@ -128,7 +128,7 @@ func (c *ApiController) DeleteToken() {
// @Title GetOAuthCode // @Title GetOAuthCode
// @Tag Token API // @Tag Token API
// @Description get OAuth code // @Description get OAuth code
// @Param user_id query string true "The id of user" // @Param id query string true "The id ( owner/name ) of user"
// @Param client_id query string true "OAuth client id" // @Param client_id query string true "OAuth client id"
// @Param response_type query string true "OAuth response type" // @Param response_type query string true "OAuth response type"
// @Param redirect_uri query string true "OAuth redirect URI" // @Param redirect_uri query string true "OAuth redirect URI"
@ -172,6 +172,7 @@ func (c *ApiController) GetOAuthCode() {
// @router /login/oauth/access_token [post] // @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() { func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type") grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
clientId := c.Input().Get("client_id") clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret") clientSecret := c.Input().Get("client_secret")
code := c.Input().Get("code") code := c.Input().Get("code")
@ -192,6 +193,7 @@ func (c *ApiController) GetOAuthToken() {
clientId = tokenRequest.ClientId clientId = tokenRequest.ClientId
clientSecret = tokenRequest.ClientSecret clientSecret = tokenRequest.ClientSecret
grantType = tokenRequest.GrantType grantType = tokenRequest.GrantType
refreshToken = tokenRequest.RefreshToken
code = tokenRequest.Code code = tokenRequest.Code
verifier = tokenRequest.Verifier verifier = tokenRequest.Verifier
scope = tokenRequest.Scope scope = tokenRequest.Scope
@ -203,7 +205,7 @@ func (c *ApiController) GetOAuthToken() {
} }
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, tag, avatar, c.GetAcceptLanguage()) c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
c.SetTokenErrorHttpStatus() c.SetTokenErrorHttpStatus()
c.ServeJSON() c.ServeJSON()
} }

View File

@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
// @Title GetUser // @Title GetUser
// @Tag User API // @Tag User API
// @Description get user // @Description get user
// @Param id query string true "The id of the user" // @Param id query string true "The id ( owner/name ) of the user"
// @Param owner query string false "The owner of the user" // @Param owner query string false "The owner of the user"
// @Param email query string false "The email of the user" // @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user" // @Param phone query string false "The phone of the user"
@ -129,7 +129,7 @@ func (c *ApiController) GetUser() {
// @Title UpdateUser // @Title UpdateUser
// @Tag User API // @Tag User API
// @Description update user // @Description update user
// @Param id query string true "The id of the user" // @Param id query string true "The id ( owner/name ) of the user"
// @Param body body object.User true "The details of the user" // @Param body body object.User true "The details of the user"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-user [post] // @router /update-user [post]

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetWebhooks() {
// @Title GetWebhook // @Title GetWebhook
// @Tag Webhook API // @Tag Webhook API
// @Description get webhook // @Description get webhook
// @Param id query string true "The id of the webhook" // @Param id query string true "The id ( owner/name ) of the webhook"
// @Success 200 {object} object.Webhook The Response object // @Success 200 {object} object.Webhook The Response object
// @router /get-webhook [get] // @router /get-webhook [get]
func (c *ApiController) GetWebhook() { func (c *ApiController) GetWebhook() {
@ -66,7 +66,7 @@ func (c *ApiController) GetWebhook() {
// @Title UpdateWebhook // @Title UpdateWebhook
// @Tag Webhook API // @Tag Webhook API
// @Description update webhook // @Description update webhook
// @Param id query string true "The id of the webhook" // @Param id query string true "The id ( owner/name ) of the webhook"
// @Param body body object.Webhook true "The details of the webhook" // @Param body body object.Webhook true "The details of the webhook"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-webhook [post] // @router /update-webhook [post]

11
go.mod
View File

@ -9,14 +9,14 @@ require (
github.com/beego/beego v1.12.11 github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.30.1 github.com/casbin/casbin/v2 v2.30.1
github.com/casbin/xorm-adapter/v3 v3.0.1
github.com/casdoor/go-sms-sender v0.5.1 github.com/casdoor/go-sms-sender v0.5.1
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/oss v1.2.0 github.com/casdoor/oss v1.2.0
github.com/casdoor/xorm-adapter/v3 v3.0.4
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.9.0 github.com/denisenkom/go-mssqldb v0.9.0
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/forestmgy/ldapserver v1.1.0 github.com/forestmgy/ldapserver v1.1.0
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-pay/gopay v1.5.72 github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
@ -41,18 +41,15 @@ require (
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
github.com/xorm-io/core v0.7.4
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.0.0-20220214200702-86341886e292 golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
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.3.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
xorm.io/builder v0.3.12 // indirect
xorm.io/core v0.7.2
xorm.io/xorm v1.1.2
) )

31
go.sum
View File

@ -58,7 +58,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -73,7 +72,6 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075 h1:Z0SzZttfYI/raZ5O9WF3cezZJTS
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
@ -96,12 +94,14 @@ github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0= github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/xorm-adapter/v3 v3.0.1 h1:0l0zkYxo6cNuIdrBZgFxlje1TRvmheYa/zIp+sGPK58=
github.com/casbin/xorm-adapter/v3 v3.0.1/go.mod h1:1BL7rHEDXrxO+vQdSo/ZaWKRivXl7YTos67GdMYcd20=
github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0= github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0=
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI= github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI=
github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8= github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss= github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss=
github.com/casdoor/xorm-adapter/v3 v3.0.4 h1:vB04Ao8n2jA7aFBI9F+gGXo9+Aa1IQP6mTdo50913DM=
github.com/casdoor/xorm-adapter/v3 v3.0.4/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -126,7 +126,6 @@ github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWW
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ= github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
@ -154,8 +153,6 @@ github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
@ -270,6 +267,7 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko= github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc= github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
@ -337,7 +335,6 @@ github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@ -456,6 +453,12 @@ github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF
github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xorm-io/builder v0.3.13 h1:J4oZxt4Gjgm/Si9iKazfzYwHB/ijEOD9EHInyjOSX+M=
github.com/xorm-io/builder v0.3.13/go.mod h1:24o5riRwzre2WvjmN+LM4YpUtJg7W8MdvJ8H57rvrJA=
github.com/xorm-io/core v0.7.4 h1:qIznlqqmYNEb03ewzRXCrNkbbxpkgc/44nVF8yoFV7Y=
github.com/xorm-io/core v0.7.4/go.mod h1:GueyhafDnkB0KK0fXX/dEhr/P1EAGW0GLmoNDUEE1Mo=
github.com/xorm-io/xorm v1.1.6 h1:s4fDpUXJx8Zr/PBovXNaadn+v1P3h/U3iV4OxAkWS8s=
github.com/xorm-io/xorm v1.1.6/go.mod h1:7nsSUdmgLIcqHSSaKOzbVQiZtzIzbpGf1GGSYp6DD70=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -520,7 +523,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -789,8 +791,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -847,12 +847,3 @@ modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v1.0.3/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
xorm.io/xorm v1.1.2 h1:bje+1KZvK3m5AHtZNfUDlKEEyuw/IRHT+an0CLIG5TU=
xorm.io/xorm v1.1.2/go.mod h1:Cb0DKYTHbyECMaSfgRnIZp5aiUgQozxcJJ0vzcLGJSg=

View File

@ -35,7 +35,10 @@ func main() {
createDatabase := flag.Bool("createDatabase", false, "true if you need Casdoor to create database") createDatabase := flag.Bool("createDatabase", false, "true if you need Casdoor to create database")
flag.Parse() flag.Parse()
object.InitAdapter(*createDatabase) object.InitAdapter()
object.DoMigration()
object.CreateTables(*createDatabase)
object.InitDb() object.InitDb()
object.InitFromFile() object.InitFromFile()
object.InitDefaultStorageProvider() object.InitDefaultStorageProvider()

View File

@ -19,16 +19,15 @@ import (
"runtime" "runtime"
"github.com/beego/beego" "github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"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"
_ "github.com/denisenkom/go-mssqldb" // db = mssql _ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql _ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres _ "github.com/lib/pq" // db = postgres
_ "modernc.org/sqlite" // db = sqlite "github.com/xorm-io/core"
"xorm.io/core" "github.com/xorm-io/xorm"
"xorm.io/xorm" _ "modernc.org/sqlite" // db = sqlite
"xorm.io/xorm/migrate"
) )
var adapter *Adapter var adapter *Adapter
@ -41,12 +40,16 @@ func InitConfig() {
beego.BConfig.WebConfig.Session.SessionOn = true beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true) InitAdapter()
initMigrations() DoMigration()
CreateTables(true)
} }
func InitAdapter(createDatabase bool) { func InitAdapter() {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName")) adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
}
func CreateTables(createDatabase bool) {
if createDatabase { if createDatabase {
adapter.CreateDatabase() adapter.CreateDatabase()
} }
@ -252,22 +255,3 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
} }
return session return session
} }
func initMigrations() {
migrations := []*migrate.Migration{
{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(tx *xorm.Engine) error {
_, err := tx.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&xormadapter.CasbinRule{})
},
},
}
m := migrate.New(adapter.Engine, migrate.DefaultOptions, migrations)
m.Migrate()
}

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type SignupItem struct { type SignupItem struct {

View File

@ -20,9 +20,9 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/core"
) )
type CasbinAdapter struct { type CasbinAdapter struct {

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Cert struct { type Cert struct {

View File

@ -19,7 +19,7 @@ package object
import ( import (
"crypto/tls" "crypto/tls"
"github.com/go-gomail/gomail" "github.com/casdoor/gomail/v2"
) )
func getDialer(provider *Provider) *gomail.Dialer { func getDialer(provider *Provider) *gomail.Dialer {
@ -45,6 +45,10 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
message.SetHeader("Subject", title) message.SetHeader("Subject", title)
message.SetBody("text/html", content) message.SetBody("text/html", content)
if provider.Type == "Mailtrap" {
message.SkipUsernameCheck = true
}
return dialer.DialAndSend(message) return dialer.DialAndSend(message)
} }

View File

@ -25,8 +25,6 @@ import (
) )
func InitDb() { func InitDb() {
MigratePermissionRule()
existed := initBuiltInOrganization() existed := initBuiltInOrganization()
if !existed { if !existed {
initBuiltInModel() initBuiltInModel()

47
object/migrator.go Normal file
View File

@ -0,0 +1,47 @@
// 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 "github.com/xorm-io/xorm/migrate"
type Migrator interface {
IsMigrationNeeded() bool
DoMigration() *migrate.Migration
}
func DoMigration() {
migrators := []Migrator{
&Migrator_1_101_0_PR_1083{},
&Migrator_1_235_0_PR_1530{},
&Migrator_1_240_0_PR_1539{},
// more migrators add here in chronological order...
}
migrations := []*migrate.Migration{}
for _, migrator := range migrators {
if migrator.IsMigrationNeeded() {
migrations = append(migrations, migrator.DoMigration())
}
}
options := &migrate.Options{
TableName: "migration",
IDColumnName: "id",
}
m := migrate.New(adapter.Engine, options, migrations)
m.Migrate()
}

View File

@ -0,0 +1,70 @@
// 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/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_101_0_PR_1083 struct{}
func (*Migrator_1_101_0_PR_1083) IsMigrationNeeded() bool {
exist1, _ := adapter.Engine.IsTableExist("model")
exist2, _ := adapter.Engine.IsTableExist("permission")
exist3, _ := adapter.Engine.IsTableExist("permission_rule")
if exist1 && exist2 && exist3 {
return true
}
return false
}
func (*Migrator_1_101_0_PR_1083) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20230209MigratePermissionRule--Use V5 instead of V1 to store permissionID",
Migrate: func(engine *xorm.Engine) error {
models := []*Model{}
err := engine.Table("model").Find(&models, &Model{})
if err != nil {
panic(err)
}
isHit := false
for _, model := range models {
if strings.Contains(model.ModelText, "permission") {
// update model table
model.ModelText = strings.Replace(model.ModelText, "permission,", "", -1)
UpdateModel(model.GetId(), model)
isHit = true
}
}
if isHit {
// update permission_rule table
sql := "UPDATE `permission_rule`SET V0 = V1, V1 = V2, V2 = V3, V3 = V4, V4 = V5 WHERE V0 IN (SELECT CONCAT(owner, '/', name) AS permission_id FROM `permission`)"
_, err = engine.Exec(sql)
if err != nil {
return err
}
}
return err
},
}
return &migration
}

View File

@ -0,0 +1,49 @@
// 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 (
xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_235_0_PR_1530 struct{}
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("casbin_rule")
if exist {
return true
}
return false
}
func (*Migrator_1_235_0_PR_1530) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(engine *xorm.Engine) error {
_, err := engine.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(engine *xorm.Engine) error {
return engine.DropTables(&xormadapter.CasbinRule{})
},
}
return &migration
}

View File

@ -0,0 +1,141 @@
// 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 (
"errors"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_240_0_PR_1539 struct{}
func (*Migrator_1_240_0_PR_1539) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("session")
err := adapter.Engine.Table("session").Find(&[]*Session{})
if exist && err != nil {
return true
}
return false
}
func (*Migrator_1_240_0_PR_1539) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20230211MigrateSession--Create a new field 'application' for table `session`",
Migrate: func(engine *xorm.Engine) error {
if alreadyCreated, _ := engine.IsTableExist("session_tmp"); alreadyCreated {
return errors.New("there is already a table called 'session_tmp', please rename or delete it for casdoor version migration and restart")
}
type oldSession struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
SessionId []string `json:"sessionId"`
}
tx := engine.NewSession()
defer tx.Close()
err := tx.Begin()
if err != nil {
return err
}
err = tx.Table("session_tmp").CreateTable(&Session{})
if err != nil {
return err
}
oldSessions := []*oldSession{}
newSessions := []*Session{}
err = tx.Table("session").Find(&oldSessions)
if err != nil {
return err
}
for _, oldSession := range oldSessions {
newApplication := "null"
if oldSession.Owner == "built-in" {
newApplication = "app-built-in"
}
newSessions = append(newSessions, &Session{
Owner: oldSession.Owner,
Name: oldSession.Name,
Application: newApplication,
CreatedTime: oldSession.CreatedTime,
SessionId: oldSession.SessionId,
})
}
rollbackFlag := false
_, err = tx.Table("session_tmp").Insert(newSessions)
count1, _ := tx.Table("session_tmp").Count()
count2, _ := tx.Table("session").Count()
if err != nil || count1 != count2 {
rollbackFlag = true
}
delete := &Session{
Application: "null",
}
_, err = tx.Table("session_tmp").Delete(*delete)
if err != nil {
rollbackFlag = true
}
if rollbackFlag {
tx.DropTable("session_tmp")
return errors.New("there is something wrong with data migration for table `session`, if there is a table called `session_tmp` not created by you in casdoor, please drop it, then restart anyhow")
}
err = tx.DropTable("session")
if err != nil {
return errors.New("fail to drop table `session` for casdoor, please drop it and rename the table `session_tmp` to `session` manually and restart")
}
// Already drop table `session`
// Can't find an api from xorm for altering table name
err = tx.Table("session").CreateTable(&Session{})
if err != nil {
return errors.New("there is something wrong with data migration for table `session`, please restart")
}
sessions := []*Session{}
tx.Table("session_tmp").Find(&sessions)
_, err = tx.Table("session").Insert(sessions)
if err != nil {
return errors.New("there is something wrong with data migration for table `session`, please drop table `session` and rename table `session_tmp` to `session` and restart")
}
err = tx.DropTable("session_tmp")
if err != nil {
return errors.New("fail to drop table `session_tmp` for casdoor, please drop it manually and restart")
}
tx.Commit()
return nil
},
}
return &migration
}

View File

@ -19,7 +19,7 @@ import (
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Model struct { type Model struct {

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/cred" "github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type AccountItem struct { type AccountItem struct {

View File

@ -19,7 +19,7 @@ import (
"net/http" "net/http"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Payment struct { type Payment struct {

View File

@ -16,10 +16,9 @@ package object
import ( import (
"fmt" "fmt"
"strings"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Permission struct { type Permission struct {
@ -269,33 +268,6 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
return permissions return permissions
} }
func MigratePermissionRule() {
models := []*Model{}
err := adapter.Engine.Find(&models, &Model{})
if err != nil {
panic(err)
}
isHit := false
for _, model := range models {
if strings.Contains(model.ModelText, "permission") {
// update model table
model.ModelText = strings.Replace(model.ModelText, "permission,", "", -1)
UpdateModel(model.GetId(), model)
isHit = true
}
}
if isHit {
// update permission_rule table
sql := "UPDATE `permission_rule`SET V0 = V1, V1 = V2, V2 = V3, V3 = V4, V4 = V5 WHERE V0 IN (SELECT CONCAT(owner, '/', name) AS permission_id FROM `permission`)"
_, err = adapter.Engine.Exec(sql)
if err != nil {
return
}
}
}
func ContainsAsterisk(userId string, users []string) bool { func ContainsAsterisk(userId string, users []string) bool {
containsAsterisk := false containsAsterisk := false
group, _ := util.GetOwnerAndNameFromId(userId) group, _ := util.GetOwnerAndNameFromId(userId)

View File

@ -21,8 +21,8 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/config" "github.com/casbin/casbin/v2/config"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
func getEnforcer(permission *Permission) *casbin.Enforcer { func getEnforcer(permission *Permission) *casbin.Enforcer {

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Product struct { type Product struct {

View File

@ -20,7 +20,7 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/pp" "github.com/casdoor/casdoor/pp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Provider struct { type Provider struct {

View File

@ -18,12 +18,12 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Resource struct { type Resource 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(180) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
User string `xorm:"varchar(100)" json:"user"` User string `xorm:"varchar(100)" json:"user"`

View File

@ -19,7 +19,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Role struct { type Role struct {

View File

@ -15,84 +15,27 @@
package object package object
import ( import (
"fmt"
"github.com/beego/beego" "github.com/beego/beego"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
)
var (
CasdoorApplication = "app-built-in"
CasdoorOrganization = "built-in"
) )
type Session struct { type Session 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"`
Application string `xorm:"varchar(100) notnull pk" json:"application"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
SessionId []string `json:"sessionId"` SessionId []string `json:"sessionId"`
} }
func SetSession(id string, sessionId string) {
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
session := &Session{Owner: owner, Name: name}
get, err := adapter.Engine.Get(session)
if err != nil {
panic(err)
}
session.SessionId = append(session.SessionId, sessionId)
if get {
_, err = adapter.Engine.ID(core.PK{owner, name}).Update(session)
} else {
session.CreatedTime = util.GetCurrentTime()
_, err = adapter.Engine.Insert(session)
}
if err != nil {
panic(err)
}
}
func DeleteSession(id string) bool {
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
session := &Session{Owner: owner, Name: name}
_, err := adapter.Engine.ID(core.PK{owner, name}).Get(session)
if err != nil {
return false
}
DeleteBeegoSession(session.SessionId)
affected, err := adapter.Engine.ID(core.PK{owner, name}).Delete(session)
return affected != 0
}
func DeleteSessionId(id string, sessionId string) bool {
owner, name := util.GetOwnerAndNameFromId(id)
session := &Session{Owner: owner, Name: name}
_, err := adapter.Engine.ID(core.PK{owner, name}).Get(session)
if err != nil {
return false
}
DeleteBeegoSession([]string{sessionId})
session.SessionId = util.DeleteVal(session.SessionId, sessionId)
if len(session.SessionId) < 1 {
affected, _ := adapter.Engine.ID(core.PK{owner, name}).Delete(session)
return affected != 0
} else {
affected, _ := adapter.Engine.ID(core.PK{owner, name}).Update(session)
return affected != 0
}
}
func DeleteBeegoSession(sessionIds []string) {
for _, sessionId := range sessionIds {
err := beego.GlobalSessions.GetProvider().SessionDestroy(sessionId)
if err != nil {
return
}
}
}
func GetSessions(owner string) []*Session { func GetSessions(owner string) []*Session {
sessions := []*Session{} sessions := []*Session{}
var err error var err error
@ -128,3 +71,131 @@ func GetSessionCount(owner, field, value string) int {
return int(count) return int(count)
} }
func GetSingleSession(id string) *Session {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
session := Session{Owner: owner, Name: name, Application: application}
get, err := adapter.Engine.Get(&session)
if err != nil {
panic(err)
}
if !get {
return nil
}
return &session
}
func UpdateSession(id string, session *Session) bool {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
if GetSingleSession(id) == nil {
return false
}
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Update(session)
if err != nil {
panic(err)
}
return affected != 0
}
func removeExtraSessionIds(session *Session) {
if len(session.SessionId) > 100 {
session.SessionId = session.SessionId[(len(session.SessionId) - 100):]
}
}
func AddSession(session *Session) bool {
dbSession := GetSingleSession(session.GetId())
if dbSession == nil {
session.CreatedTime = util.GetCurrentTime()
affected, err := adapter.Engine.Insert(session)
if err != nil {
panic(err)
}
return affected != 0
} else {
m := make(map[string]struct{})
for _, v := range dbSession.SessionId {
m[v] = struct{}{}
}
for _, v := range session.SessionId {
if _, exists := m[v]; !exists {
dbSession.SessionId = append(dbSession.SessionId, v)
}
}
removeExtraSessionIds(dbSession)
return UpdateSession(dbSession.GetId(), dbSession)
}
}
func DeleteSession(id string) bool {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
if owner == CasdoorOrganization && application == CasdoorApplication {
session := GetSingleSession(id)
if session != nil {
DeleteBeegoSession(session.SessionId)
}
}
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Delete(&Session{})
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteSessionId(id string, sessionId string) bool {
session := GetSingleSession(id)
if session == nil {
return false
}
owner, _, application := util.GetOwnerAndNameAndOtherFromId(id)
if owner == CasdoorOrganization && application == CasdoorApplication {
DeleteBeegoSession([]string{sessionId})
}
session.SessionId = util.DeleteVal(session.SessionId, sessionId)
if len(session.SessionId) == 0 {
return DeleteSession(id)
} else {
return UpdateSession(id, session)
}
}
func DeleteBeegoSession(sessionIds []string) {
for _, sessionId := range sessionIds {
err := beego.GlobalSessions.GetProvider().SessionDestroy(sessionId)
if err != nil {
return
}
}
}
func (session *Session) GetId() string {
return fmt.Sprintf("%s/%s/%s", session.Owner, session.Name, session.Application)
}
func IsSessionDuplicated(id string, sessionId string) bool {
session := GetSingleSession(id)
if session == nil {
return false
} else {
if len(session.SessionId) > 1 {
return true
} else if len(session.SessionId) < 1 {
return false
} else {
return session.SessionId[0] != sessionId
}
}
}

View File

@ -18,6 +18,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"net/url" "net/url"
"path/filepath"
"strings" "strings"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
@ -54,6 +55,25 @@ func escapePath(path string) string {
return res return res
} }
func GetTruncatedPath(provider *Provider, fullFilePath string, limit int) string {
pathPrefix := util.UrlJoin(util.GetUrlPath(provider.Domain), provider.PathPrefix)
dir, file := filepath.Split(fullFilePath)
ext := filepath.Ext(file)
fileName := strings.TrimSuffix(file, ext)
for {
escapedString := escapePath(escapePath(fullFilePath))
if len(escapedString) < limit-len(pathPrefix) {
break
}
rs := []rune(fileName)
fileName = string(rs[0 : len(rs)-1])
fullFilePath = dir + fileName + ext
}
return fullFilePath
}
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) { func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath)) escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath) objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
@ -74,10 +94,15 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
} }
fileUrl := util.UrlJoin(host, escapePath(objectKey)) fileUrl := util.UrlJoin(host, escapePath(objectKey))
if hasTimestamp { if hasTimestamp {
fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime()) fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
} }
if provider.Type == "Tencent Cloud COS" {
objectKey = escapePath(objectKey)
}
return fileUrl, objectKey return fileUrl, objectKey
} }

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type TableColumn struct { type TableColumn struct {

View File

@ -20,7 +20,7 @@ import (
"time" "time"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type OriginalUser = User type OriginalUser = User

View File

@ -23,11 +23,11 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
hourMinutes = 60 hourSeconds = int(time.Hour / time.Second)
InvalidRequest = "invalid_request" InvalidRequest = "invalid_request"
InvalidClient = "invalid_client" InvalidClient = "invalid_client"
InvalidGrant = "invalid_grant" InvalidGrant = "invalid_grant"
@ -306,7 +306,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeChallenge: challenge, CodeChallenge: challenge,
@ -321,7 +321,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
} }
} }
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, tag string, avatar string, lang string) interface{} { func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, refreshToken string, tag string, avatar string, lang string) interface{} {
application := GetApplicationByClientId(clientId) application := GetApplicationByClientId(clientId)
if application == nil { if application == nil {
return &TokenError{ return &TokenError{
@ -348,6 +348,8 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
token, tokenError = GetPasswordToken(application, username, password, scope, host) token, tokenError = GetPasswordToken(application, username, password, scope, host)
case "client_credentials": // Client Credentials Grant case "client_credentials": // Client Credentials Grant
token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host) token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host)
case "refresh_token":
return RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
} }
if tag == "wechat_miniprogram" { if tag == "wechat_miniprogram" {
@ -440,7 +442,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: newAccessToken, AccessToken: newAccessToken,
RefreshToken: newRefreshToken, RefreshToken: newRefreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
} }
@ -590,7 +592,7 @@ func GetPasswordToken(application *Application, username string, password string
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,
@ -630,7 +632,7 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
User: nullUser.Name, User: nullUser.Name,
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,
@ -657,7 +659,7 @@ func GetTokenByUser(application *Application, user *User, scope string, host str
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,

View File

@ -265,8 +265,8 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims) claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp) token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime) claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claims.TokenType = "refresh-token" claimsWithoutThirdIdp.TokenType = "refresh-token"
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp) refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
} }

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn" "github.com/duo-labs/webauthn/webauthn"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
@ -578,7 +578,7 @@ func AddUsersInBatch(users []*User) bool {
func DeleteUser(user *User) bool { func DeleteUser(user *User) bool {
// Forced offline the user first // Forced offline the user first
DeleteSession(user.GetId()) DeleteSession(util.GetSessionId(user.Owner, user.Name, CasdoorApplication))
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{}) affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ import (
"testing" "testing"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
func updateUserColumn(column string, user *User) bool { func updateUserColumn(column string, user *User) bool {

View File

@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"xorm.io/core" "github.com/xorm-io/core"
) )
func GetUserByField(organizationName string, field string, value string) *User { func GetUserByField(organizationName string, field string, value string) *User {

View File

@ -23,7 +23,7 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Header struct { type Header struct {

View File

@ -163,7 +163,11 @@ func initAPI() {
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord") beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions") beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
beego.Router("/api/update-session", &controllers.ApiController{}, "POST:UpdateSession")
beego.Router("/api/add-session", &controllers.ApiController{}, "POST:AddSession")
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession") beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
beego.Router("/api/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks") beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook") beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")

View File

@ -578,7 +578,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the product", "description": "The id ( owner/name ) of the product",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -894,8 +894,8 @@
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
"name": "ID", "name": "id",
"description": "The ID(owner/name) of user.", "description": "The id ( owner/name )(owner/name) of user.",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1107,7 +1107,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the application.", "description": "The id ( owner/name ) of the application.",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1162,7 +1162,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the cert", "description": "The id ( owner/name ) of the cert",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1340,7 +1340,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the model", "description": "The id ( owner/name ) of the model",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1479,7 +1479,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the payment", "description": "The id ( owner/name ) of the payment",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1534,7 +1534,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the permission", "description": "The id ( owner/name ) of the permission",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1589,7 +1589,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the role", "description": "The id ( owner/name ) of the role",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1638,7 +1638,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the product", "description": "The id ( owner/name ) of the product",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1693,7 +1693,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the provider", "description": "The id ( owner/name ) of the provider",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1840,7 +1840,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the role", "description": "The id ( owner/name ) of the role",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1966,7 +1966,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the syncer", "description": "The id ( owner/name ) of the syncer",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2021,7 +2021,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the user", "description": "The id ( owner/name ) of the user",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2047,7 +2047,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of token", "description": "The id ( owner/name ) of token",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2116,7 +2116,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the user", "description": "The id ( owner/name ) of the user",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -2160,7 +2160,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the user", "description": "The id ( owner/name ) of the user",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2286,7 +2286,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the webhook", "description": "The id ( owner/name ) of the webhook",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2341,7 +2341,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the payment", "description": "The id ( owner/name ) of the payment",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -2504,8 +2504,8 @@
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
"name": "user_id", "name": "id",
"description": "The id of user", "description": "The id ( owner/name ) of user",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -2904,7 +2904,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the application", "description": "The id ( owner/name ) of the application",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -2939,7 +2939,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the cert", "description": "The id ( owner/name ) of the cert",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -2982,7 +2982,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the model", "description": "The id ( owner/name ) of the model",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3017,7 +3017,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the organization", "description": "The id ( owner/name ) of the organization",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3052,7 +3052,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the payment", "description": "The id ( owner/name ) of the payment",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3087,7 +3087,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the permission", "description": "The id ( owner/name ) of the permission",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3122,7 +3122,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the product", "description": "The id ( owner/name ) of the product",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3157,7 +3157,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the provider", "description": "The id ( owner/name ) of the provider",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3200,7 +3200,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the role", "description": "The id ( owner/name ) of the role",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3235,7 +3235,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the syncer", "description": "The id ( owner/name ) of the syncer",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3270,7 +3270,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of token", "description": "The id ( owner/name ) of token",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3305,7 +3305,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the user", "description": "The id ( owner/name ) of the user",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3340,7 +3340,7 @@
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id of the webhook", "description": "The id ( owner/name ) of the webhook",
"required": true, "required": true,
"type": "string" "type": "string"
}, },
@ -3505,11 +3505,11 @@
} }
}, },
"definitions": { "definitions": {
"2268.0xc0000f9650.false": { "2346.0xc0001ce990.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"2302.0xc0000f9680.false": { "2381.0xc0001ce9c0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
@ -3636,10 +3636,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2268.0xc0000f9650.false" "$ref": "#/definitions/2346.0xc0001ce990.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2302.0xc0000f9680.false" "$ref": "#/definitions/2381.0xc0001ce9c0.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@ -3846,6 +3846,9 @@
"termsOfUse": { "termsOfUse": {
"type": "string" "type": "string"
}, },
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"tokenFormat": { "tokenFormat": {
"type": "string" "type": "string"
} }
@ -4143,6 +4146,9 @@
"type": "string" "type": "string"
} }
}, },
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"websiteUrl": { "websiteUrl": {
"type": "string" "type": "string"
} }
@ -4727,6 +4733,28 @@
} }
} }
}, },
"object.ThemeData": {
"title": "ThemeData",
"type": "object",
"properties": {
"borderRadius": {
"type": "integer",
"format": "int64"
},
"colorPrimary": {
"type": "string"
},
"isCompact": {
"type": "boolean"
},
"isEnabled": {
"type": "boolean"
},
"themeType": {
"type": "string"
}
}
},
"object.Token": { "object.Token": {
"title": "Token", "title": "Token",
"type": "object", "type": "object",
@ -4836,9 +4864,15 @@
"alipay": { "alipay": {
"type": "string" "type": "string"
}, },
"amazon": {
"type": "string"
},
"apple": { "apple": {
"type": "string" "type": "string"
}, },
"auth0": {
"type": "string"
},
"avatar": { "avatar": {
"type": "string" "type": "string"
}, },
@ -4848,6 +4882,9 @@
"baidu": { "baidu": {
"type": "string" "type": "string"
}, },
"battlenet": {
"type": "string"
},
"bilibili": { "bilibili": {
"type": "string" "type": "string"
}, },
@ -4857,9 +4894,18 @@
"birthday": { "birthday": {
"type": "string" "type": "string"
}, },
"bitbucket": {
"type": "string"
},
"box": {
"type": "string"
},
"casdoor": { "casdoor": {
"type": "string" "type": "string"
}, },
"cloudfoundry": {
"type": "string"
},
"createdIp": { "createdIp": {
"type": "string" "type": "string"
}, },
@ -4869,15 +4915,30 @@
"custom": { "custom": {
"type": "string" "type": "string"
}, },
"dailymotion": {
"type": "string"
},
"deezer": {
"type": "string"
},
"digitalocean": {
"type": "string"
},
"dingtalk": { "dingtalk": {
"type": "string" "type": "string"
}, },
"discord": {
"type": "string"
},
"displayName": { "displayName": {
"type": "string" "type": "string"
}, },
"douyin": { "douyin": {
"type": "string" "type": "string"
}, },
"dropbox": {
"type": "string"
},
"education": { "education": {
"type": "string" "type": "string"
}, },
@ -4887,15 +4948,24 @@
"emailVerified": { "emailVerified": {
"type": "boolean" "type": "boolean"
}, },
"eveonline": {
"type": "string"
},
"facebook": { "facebook": {
"type": "string" "type": "string"
}, },
"firstName": { "firstName": {
"type": "string" "type": "string"
}, },
"fitbit": {
"type": "string"
},
"gender": { "gender": {
"type": "string" "type": "string"
}, },
"gitea": {
"type": "string"
},
"gitee": { "gitee": {
"type": "string" "type": "string"
}, },
@ -4911,6 +4981,9 @@
"hash": { "hash": {
"type": "string" "type": "string"
}, },
"heroku": {
"type": "string"
},
"homepage": { "homepage": {
"type": "string" "type": "string"
}, },
@ -4923,9 +4996,18 @@
"idCardType": { "idCardType": {
"type": "string" "type": "string"
}, },
"influxcloud": {
"type": "string"
},
"infoflow": { "infoflow": {
"type": "string" "type": "string"
}, },
"instagram": {
"type": "string"
},
"intercom": {
"type": "string"
},
"isAdmin": { "isAdmin": {
"type": "boolean" "type": "boolean"
}, },
@ -4944,6 +5026,9 @@
"isOnline": { "isOnline": {
"type": "boolean" "type": "boolean"
}, },
"kakao": {
"type": "string"
},
"karma": { "karma": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@ -4966,6 +5051,9 @@
"lastSigninWrongTime": { "lastSigninWrongTime": {
"type": "string" "type": "string"
}, },
"lastfm": {
"type": "string"
},
"ldap": { "ldap": {
"type": "string" "type": "string"
}, },
@ -4978,18 +5066,39 @@
"location": { "location": {
"type": "string" "type": "string"
}, },
"mailru": {
"type": "string"
},
"managedAccounts": { "managedAccounts": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/object.ManagedAccount" "$ref": "#/definitions/object.ManagedAccount"
} }
}, },
"meetup": {
"type": "string"
},
"microsoftonline": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
}, },
"naver": {
"type": "string"
},
"nextcloud": {
"type": "string"
},
"okta": { "okta": {
"type": "string" "type": "string"
}, },
"onedrive": {
"type": "string"
},
"oura": {
"type": "string"
},
"owner": { "owner": {
"type": "string" "type": "string"
}, },
@ -4999,6 +5108,12 @@
"passwordSalt": { "passwordSalt": {
"type": "string" "type": "string"
}, },
"patreon": {
"type": "string"
},
"paypal": {
"type": "string"
},
"permanentAvatar": { "permanentAvatar": {
"type": "string" "type": "string"
}, },
@ -5035,10 +5150,16 @@
"$ref": "#/definitions/object.Role" "$ref": "#/definitions/object.Role"
} }
}, },
"salesforce": {
"type": "string"
},
"score": { "score": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
}, },
"shopify": {
"type": "string"
},
"signinWrongTimes": { "signinWrongTimes": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@ -5049,21 +5170,54 @@
"slack": { "slack": {
"type": "string" "type": "string"
}, },
"soundcloud": {
"type": "string"
},
"spotify": {
"type": "string"
},
"steam": { "steam": {
"type": "string" "type": "string"
}, },
"strava": {
"type": "string"
},
"stripe": {
"type": "string"
},
"tag": { "tag": {
"type": "string" "type": "string"
}, },
"tiktok": {
"type": "string"
},
"title": { "title": {
"type": "string" "type": "string"
}, },
"tumblr": {
"type": "string"
},
"twitch": {
"type": "string"
},
"twitter": {
"type": "string"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
"typetalk": {
"type": "string"
},
"uber": {
"type": "string"
},
"updatedTime": { "updatedTime": {
"type": "string" "type": "string"
}, },
"vk": {
"type": "string"
},
"webauthnCredentials": { "webauthnCredentials": {
"type": "array", "type": "array",
"items": { "items": {
@ -5078,6 +5232,24 @@
}, },
"weibo": { "weibo": {
"type": "string" "type": "string"
},
"wepay": {
"type": "string"
},
"xero": {
"type": "string"
},
"yahoo": {
"type": "string"
},
"yammer": {
"type": "string"
},
"yandex": {
"type": "string"
},
"zoom": {
"type": "string"
} }
} }
}, },

View File

@ -375,7 +375,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the product description: The id ( owner/name ) of the product
required: true required: true
type: string type: string
- in: query - in: query
@ -578,8 +578,8 @@ paths:
operationId: ApiController.DeleteSession operationId: ApiController.DeleteSession
parameters: parameters:
- in: query - in: query
name: ID name: id
description: The ID(owner/name) of user. description: The id ( owner/name )(owner/name) of user.
required: true required: true
type: string type: string
responses: responses:
@ -718,7 +718,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the application. description: The id ( owner/name ) of the application.
required: true required: true
type: string type: string
responses: responses:
@ -754,7 +754,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the cert description: The id ( owner/name ) of the cert
required: true required: true
type: string type: string
responses: responses:
@ -870,7 +870,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the model description: The id ( owner/name ) of the model
required: true required: true
type: string type: string
responses: responses:
@ -961,7 +961,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the payment description: The id ( owner/name ) of the payment
required: true required: true
type: string type: string
responses: responses:
@ -997,7 +997,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the permission description: The id ( owner/name ) of the permission
required: true required: true
type: string type: string
responses: responses:
@ -1033,7 +1033,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the role description: The id ( owner/name ) of the role
required: true required: true
type: string type: string
responses: responses:
@ -1065,7 +1065,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the product description: The id ( owner/name ) of the product
required: true required: true
type: string type: string
responses: responses:
@ -1101,7 +1101,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the provider description: The id ( owner/name ) of the provider
required: true required: true
type: string type: string
responses: responses:
@ -1197,7 +1197,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the role description: The id ( owner/name ) of the role
required: true required: true
type: string type: string
responses: responses:
@ -1280,7 +1280,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the syncer description: The id ( owner/name ) of the syncer
required: true required: true
type: string type: string
responses: responses:
@ -1316,7 +1316,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the user description: The id ( owner/name ) of the user
required: true required: true
type: string type: string
responses: responses:
@ -1333,7 +1333,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of token description: The id ( owner/name ) of token
required: true required: true
type: string type: string
responses: responses:
@ -1379,7 +1379,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the user description: The id ( owner/name ) of the user
required: true required: true
type: string type: string
- in: query - in: query
@ -1408,7 +1408,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the user description: The id ( owner/name ) of the user
required: true required: true
type: string type: string
responses: responses:
@ -1491,7 +1491,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the webhook description: The id ( owner/name ) of the webhook
required: true required: true
type: string type: string
responses: responses:
@ -1527,7 +1527,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the payment description: The id ( owner/name ) of the payment
required: true required: true
type: string type: string
responses: responses:
@ -1636,8 +1636,8 @@ paths:
operationId: ApiController.GetOAuthCode operationId: ApiController.GetOAuthCode
parameters: parameters:
- in: query - in: query
name: user_id name: id
description: The id of user description: The id ( owner/name ) of user
required: true required: true
type: string type: string
- in: query - in: query
@ -1902,7 +1902,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the application description: The id ( owner/name ) of the application
required: true required: true
type: string type: string
- in: body - in: body
@ -1925,7 +1925,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the cert description: The id ( owner/name ) of the cert
required: true required: true
type: string type: string
- in: body - in: body
@ -1953,7 +1953,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the model description: The id ( owner/name ) of the model
required: true required: true
type: string type: string
- in: body - in: body
@ -1976,7 +1976,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the organization description: The id ( owner/name ) of the organization
required: true required: true
type: string type: string
- in: body - in: body
@ -1999,7 +1999,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the payment description: The id ( owner/name ) of the payment
required: true required: true
type: string type: string
- in: body - in: body
@ -2022,7 +2022,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the permission description: The id ( owner/name ) of the permission
required: true required: true
type: string type: string
- in: body - in: body
@ -2045,7 +2045,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the product description: The id ( owner/name ) of the product
required: true required: true
type: string type: string
- in: body - in: body
@ -2068,7 +2068,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the provider description: The id ( owner/name ) of the provider
required: true required: true
type: string type: string
- in: body - in: body
@ -2096,7 +2096,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the role description: The id ( owner/name ) of the role
required: true required: true
type: string type: string
- in: body - in: body
@ -2119,7 +2119,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the syncer description: The id ( owner/name ) of the syncer
required: true required: true
type: string type: string
- in: body - in: body
@ -2142,7 +2142,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of token description: The id ( owner/name ) of token
required: true required: true
type: string type: string
- in: body - in: body
@ -2165,7 +2165,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the user description: The id ( owner/name ) of the user
required: true required: true
type: string type: string
- in: body - in: body
@ -2188,7 +2188,7 @@ paths:
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id of the webhook description: The id ( owner/name ) of the webhook
required: true required: true
type: string type: string
- in: body - in: body
@ -2293,10 +2293,10 @@ paths:
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
definitions: definitions:
2268.0xc0000f9650.false: 2346.0xc0001ce990.false:
title: "false" title: "false"
type: object type: object
2302.0xc0000f9680.false: 2381.0xc0001ce9c0.false:
title: "false" title: "false"
type: object type: object
Response: Response:
@ -2383,9 +2383,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2268.0xc0000f9650.false' $ref: '#/definitions/2346.0xc0001ce990.false'
data2: data2:
$ref: '#/definitions/2302.0xc0000f9680.false' $ref: '#/definitions/2381.0xc0001ce9c0.false'
msg: msg:
type: string type: string
name: name:
@ -2524,6 +2524,8 @@ definitions:
type: string type: string
termsOfUse: termsOfUse:
type: string type: string
themeData:
$ref: '#/definitions/object.ThemeData'
tokenFormat: tokenFormat:
type: string type: string
object.Cert: object.Cert:
@ -2724,6 +2726,8 @@ definitions:
type: array type: array
items: items:
type: string type: string
themeData:
$ref: '#/definitions/object.ThemeData'
websiteUrl: websiteUrl:
type: string type: string
object.Payment: object.Payment:
@ -3115,6 +3119,21 @@ definitions:
type: array type: array
items: items:
type: string type: string
object.ThemeData:
title: ThemeData
type: object
properties:
borderRadius:
type: integer
format: int64
colorPrimary:
type: string
isCompact:
type: boolean
isEnabled:
type: boolean
themeType:
type: string
object.Token: object.Token:
title: Token title: Token
type: object type: object
@ -3190,46 +3209,74 @@ definitions:
type: string type: string
alipay: alipay:
type: string type: string
amazon:
type: string
apple: apple:
type: string type: string
auth0:
type: string
avatar: avatar:
type: string type: string
azuread: azuread:
type: string type: string
baidu: baidu:
type: string type: string
battlenet:
type: string
bilibili: bilibili:
type: string type: string
bio: bio:
type: string type: string
birthday: birthday:
type: string type: string
bitbucket:
type: string
box:
type: string
casdoor: casdoor:
type: string type: string
cloudfoundry:
type: string
createdIp: createdIp:
type: string type: string
createdTime: createdTime:
type: string type: string
custom: custom:
type: string type: string
dailymotion:
type: string
deezer:
type: string
digitalocean:
type: string
dingtalk: dingtalk:
type: string type: string
discord:
type: string
displayName: displayName:
type: string type: string
douyin: douyin:
type: string type: string
dropbox:
type: string
education: education:
type: string type: string
email: email:
type: string type: string
emailVerified: emailVerified:
type: boolean type: boolean
eveonline:
type: string
facebook: facebook:
type: string type: string
firstName: firstName:
type: string type: string
fitbit:
type: string
gender: gender:
type: string type: string
gitea:
type: string
gitee: gitee:
type: string type: string
github: github:
@ -3240,6 +3287,8 @@ definitions:
type: string type: string
hash: hash:
type: string type: string
heroku:
type: string
homepage: homepage:
type: string type: string
id: id:
@ -3248,8 +3297,14 @@ definitions:
type: string type: string
idCardType: idCardType:
type: string type: string
influxcloud:
type: string
infoflow: infoflow:
type: string type: string
instagram:
type: string
intercom:
type: string
isAdmin: isAdmin:
type: boolean type: boolean
isDefaultAvatar: isDefaultAvatar:
@ -3262,6 +3317,8 @@ definitions:
type: boolean type: boolean
isOnline: isOnline:
type: boolean type: boolean
kakao:
type: string
karma: karma:
type: integer type: integer
format: int64 format: int64
@ -3277,6 +3334,8 @@ definitions:
type: string type: string
lastSigninWrongTime: lastSigninWrongTime:
type: string type: string
lastfm:
type: string
ldap: ldap:
type: string type: string
line: line:
@ -3285,20 +3344,38 @@ definitions:
type: string type: string
location: location:
type: string type: string
mailru:
type: string
managedAccounts: managedAccounts:
type: array type: array
items: items:
$ref: '#/definitions/object.ManagedAccount' $ref: '#/definitions/object.ManagedAccount'
meetup:
type: string
microsoftonline:
type: string
name: name:
type: string type: string
naver:
type: string
nextcloud:
type: string
okta: okta:
type: string type: string
onedrive:
type: string
oura:
type: string
owner: owner:
type: string type: string
password: password:
type: string type: string
passwordSalt: passwordSalt:
type: string type: string
patreon:
type: string
paypal:
type: string
permanentAvatar: permanentAvatar:
type: string type: string
permissions: permissions:
@ -3323,9 +3400,13 @@ definitions:
type: array type: array
items: items:
$ref: '#/definitions/object.Role' $ref: '#/definitions/object.Role'
salesforce:
type: string
score: score:
type: integer type: integer
format: int64 format: int64
shopify:
type: string
signinWrongTimes: signinWrongTimes:
type: integer type: integer
format: int64 format: int64
@ -3333,16 +3414,38 @@ definitions:
type: string type: string
slack: slack:
type: string type: string
soundcloud:
type: string
spotify:
type: string
steam: steam:
type: string type: string
strava:
type: string
stripe:
type: string
tag: tag:
type: string type: string
tiktok:
type: string
title: title:
type: string type: string
tumblr:
type: string
twitch:
type: string
twitter:
type: string
type: type:
type: string type: string
typetalk:
type: string
uber:
type: string
updatedTime: updatedTime:
type: string type: string
vk:
type: string
webauthnCredentials: webauthnCredentials:
type: array type: array
items: items:
@ -3353,6 +3456,18 @@ definitions:
type: string type: string
weibo: weibo:
type: string type: string
wepay:
type: string
xero:
type: string
yahoo:
type: string
yammer:
type: string
yandex:
type: string
zoom:
type: string
object.Userinfo: object.Userinfo:
title: Userinfo title: Userinfo
type: object type: object

View File

@ -100,6 +100,15 @@ func GetOwnerAndNameFromIdNoCheck(id string) (string, string) {
return tokens[0], tokens[1] return tokens[0], tokens[1]
} }
func GetOwnerAndNameAndOtherFromId(id string) (string, string, string) {
tokens := strings.Split(id, "/")
if len(tokens) != 3 {
panic(errors.New("GetOwnerAndNameAndOtherFromId() error, wrong token count for ID: " + id))
}
return tokens[0], tokens[1], tokens[2]
}
func GenerateId() string { func GenerateId() string {
return uuid.NewString() return uuid.NewString()
} }
@ -127,6 +136,10 @@ func GetId(owner, name string) string {
return fmt.Sprintf("%s/%s", owner, name) return fmt.Sprintf("%s/%s", owner, name)
} }
func GetSessionId(owner, name, application string) string {
return fmt.Sprintf("%s/%s/%s", owner, name, application)
}
func GetMd5Hash(text string) string { func GetMd5Hash(text string) string {
hash := md5.Sum([]byte(text)) hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:]) return hex.EncodeToString(hash[:])

View File

@ -14,7 +14,7 @@
package util package util
import xormadapter "github.com/casbin/xorm-adapter/v3" import xormadapter "github.com/casdoor/xorm-adapter/v3"
func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string { func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
s := []string{ s := []string{

View File

@ -31,6 +31,6 @@ func GetCurrentUnixTime() string {
func IsTokenExpired(createdTime string, expiresIn int) bool { func IsTokenExpired(createdTime string, expiresIn int) bool {
createdTimeObj, _ := time.Parse(time.RFC3339, createdTime) createdTimeObj, _ := time.Parse(time.RFC3339, createdTime)
expiresAtObj := createdTimeObj.Add(time.Duration(expiresIn) * time.Minute) expiresAtObj := createdTimeObj.Add(time.Duration(expiresIn) * time.Second)
return time.Now().After(expiresAtObj) return time.Now().After(expiresAtObj)
} }

View File

@ -56,15 +56,15 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted now is valid for 60 minutes", description: "Token emitted now is valid for 60 minutes",
input: input{ input: input{
createdTime: time.Now().Format(time.RFC3339), createdTime: time.Now().Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emitted 60 minutes before now is valid for 60 minutes", description: "Token emitted 60 minutes before now is valid for 61 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339),
expiresIn: 61, expiresIn: 3660,
}, },
expected: false, expected: false,
}, },
@ -72,7 +72,7 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted 2 hours before now is Expired after 60 minutes", description: "Token emitted 2 hours before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
@ -80,23 +80,23 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted 61 minutes before now is Expired after 60 minutes", description: "Token emitted 61 minutes before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
{ {
description: "Token emitted 2 hours before now is valid for 120 minutes", description: "Token emitted 2 hours before now is valid for 121 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 121, expiresIn: 7260,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emitted 159 minutes before now is Expired after 60 minutes", description: "Token emitted 159 minutes before now is Expired after 120 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339),
expiresIn: 120, expiresIn: 7200,
}, },
expected: true, expected: true,
}, },

View File

@ -84,8 +84,8 @@ class App extends Component {
uri: null, uri: null,
menuVisible: false, menuVisible: false,
themeAlgorithm: ["default"], themeAlgorithm: ["default"],
themeData: Setting.ThemeDefault, themeData: Conf.ThemeDefault,
logo: this.getLogo(Setting.getAlgorithmNames(Setting.ThemeDefault)), logo: this.getLogo(Setting.getAlgorithmNames(Conf.ThemeDefault)),
}; };
Setting.initServerUrl(); Setting.initServerUrl();
@ -554,6 +554,13 @@ class App extends Component {
}; };
renderContent() { renderContent() {
const onClick = ({key}) => {
if (key === "/swagger") {
window.open(Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger", "_blank");
} else {
this.props.history.push(key);
}
};
return ( return (
<Layout id="parent-area"> <Layout id="parent-area">
{/* https://github.com/ant-design/ant-design/issues/40394 ant design bug. If it will be fixed, we can delete the code for control the color of Header*/} {/* https://github.com/ant-design/ant-design/issues/40394 ant design bug. If it will be fixed, we can delete the code for control the color of Header*/}
@ -580,6 +587,7 @@ class App extends Component {
</Button> </Button>
</React.Fragment> : </React.Fragment> :
<Menu <Menu
onClick={onClick}
items={this.getMenuItems()} items={this.getMenuItems()}
mode={"horizontal"} mode={"horizontal"}
selectedKeys={[this.state.selectedMenuKey]} selectedKeys={[this.state.selectedMenuKey]}

View File

@ -18,6 +18,7 @@ import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
import * as ApplicationBackend from "./backend/ApplicationBackend"; import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as CertBackend from "./backend/CertBackend"; import * as CertBackend from "./backend/CertBackend";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import * as ProviderBackend from "./backend/ProviderBackend"; import * as ProviderBackend from "./backend/ProviderBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend"; import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ResourceBackend from "./backend/ResourceBackend"; import * as ResourceBackend from "./backend/ResourceBackend";
@ -717,7 +718,7 @@ class ApplicationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}> <Col span={22} style={{marginTop: "5px"}}>
<Row> <Row>
<Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => { <Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.application.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {_, ...theme} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value}); this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value});
}} > }} >
<Radio.Button value={false}>{i18next.t("application:Follow organization theme")}</Radio.Button> <Radio.Button value={false}>{i18next.t("application:Follow organization theme")}</Radio.Button>
@ -728,7 +729,7 @@ class ApplicationEditPage extends React.Component {
this.state.application.themeData?.isEnabled ? this.state.application.themeData?.isEnabled ?
<Row style={{marginTop: "20px"}}> <Row style={{marginTop: "20px"}}>
<ThemeEditor themeData={this.state.application.themeData} onThemeChange={(_, nextThemeData) => { <ThemeEditor themeData={this.state.application.themeData} onThemeChange={(_, nextThemeData) => {
const {isEnabled} = this.state.application.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {isEnabled} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateApplicationField("themeData", {...nextThemeData, isEnabled}); this.updateApplicationField("themeData", {...nextThemeData, isEnabled});
}} /> }} />
</Row> : null </Row> : null
@ -764,7 +765,7 @@ class ApplicationEditPage extends React.Component {
} }
renderSignupSigninPreview() { renderSignupSigninPreview() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault; const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
let signUpUrl = `/signup/${this.state.application.name}`; let signUpUrl = `/signup/${this.state.application.name}`;
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`; const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`;
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"}; const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"};
@ -835,7 +836,7 @@ class ApplicationEditPage extends React.Component {
} }
renderPromptPreview() { renderPromptPreview() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault; const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
const promptUrl = `/prompt/${this.state.application.name}`; const promptUrl = `/prompt/${this.state.application.name}`;
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"}; const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
return ( return (

View File

@ -17,6 +17,13 @@ export const GithubRepo = "https://github.com/casdoor/casdoor";
export const ForceLanguage = ""; export const ForceLanguage = "";
export const DefaultLanguage = "en"; export const DefaultLanguage = "en";
export const InitThemeAlgorithm = true;
export const EnableExtraPages = true; export const EnableExtraPages = true;
export const InitThemeAlgorithm = true;
export const ThemeDefault = {
themeType: "default",
colorPrimary: "#5734d3",
borderRadius: 6,
isCompact: false,
};

View File

@ -17,6 +17,7 @@ import {Redirect, Route, Switch} from "react-router-dom";
import {Spin} from "antd"; import {Spin} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import SignupPage from "./auth/SignupPage"; import SignupPage from "./auth/SignupPage";
import SelfLoginPage from "./auth/SelfLoginPage"; import SelfLoginPage from "./auth/SelfLoginPage";
import LoginPage from "./auth/LoginPage"; import LoginPage from "./auth/LoginPage";
@ -62,7 +63,7 @@ class EntryPage extends React.Component {
application: application, application: application,
}); });
const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Setting.ThemeDefault; const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault;
this.props.updataThemeData(themeData); this.props.updataThemeData(themeData);
}; };
@ -82,8 +83,8 @@ class EntryPage extends React.Component {
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} {...props} />)} /> <Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signup"} {...props} />);}} /> <Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signup"} onUpdateApplication={onUpdateApplication} {...props} />);}} />
</Switch> </Switch>
</div> </div>
); );

View File

@ -18,6 +18,7 @@ import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ApplicationBackend from "./backend/ApplicationBackend"; import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as LdapBackend from "./backend/LdapBackend"; import * as LdapBackend from "./backend/LdapBackend";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import i18next from "i18next"; import i18next from "i18next";
import {LinkOutlined} from "@ant-design/icons"; import {LinkOutlined} from "@ant-design/icons";
import LdapTable from "./LdapTable"; import LdapTable from "./LdapTable";
@ -324,7 +325,7 @@ class OrganizationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}> <Col span={22} style={{marginTop: "5px"}}>
<Row> <Row>
<Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => { <Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.organization.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {_, ...theme} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value}); this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value});
}} > }} >
<Radio.Button value={false}>{i18next.t("organization:Follow global theme")}</Radio.Button> <Radio.Button value={false}>{i18next.t("organization:Follow global theme")}</Radio.Button>
@ -335,7 +336,7 @@ class OrganizationEditPage extends React.Component {
this.state.organization.themeData?.isEnabled ? this.state.organization.themeData?.isEnabled ?
<Row style={{marginTop: "20px"}}> <Row style={{marginTop: "20px"}}>
<ThemeEditor themeData={this.state.organization.themeData} onThemeChange={(_, nextThemeData) => { <ThemeEditor themeData={this.state.organization.themeData} onThemeChange={(_, nextThemeData) => {
const {isEnabled} = this.state.organization.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {isEnabled} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateOrganizationField("themeData", {...nextThemeData, isEnabled}); this.updateOrganizationField("themeData", {...nextThemeData, isEnabled});
}} /> }} />
</Row> : null </Row> : null

View File

@ -141,6 +141,8 @@ class ProviderListPage extends BaseListPage {
{text: "SMS", value: "SMS"}, {text: "SMS", value: "SMS"},
{text: "Storage", value: "Storage"}, {text: "Storage", value: "Storage"},
{text: "SAML", value: "SAML"}, {text: "SAML", value: "SAML"},
{text: "Captcha", value: "Captcha"},
{text: "Payment", value: "Payment"},
], ],
width: "110px", width: "110px",
sorter: true, sorter: true,
@ -159,6 +161,7 @@ class ProviderListPage extends BaseListPage {
{text: "Storage", value: "Storage", children: Setting.getProviderTypeOptions("Storage").map((o) => {return {text: o.id, value: o.name};})}, {text: "Storage", value: "Storage", children: Setting.getProviderTypeOptions("Storage").map((o) => {return {text: o.id, value: o.name};})},
{text: "SAML", value: "SAML", children: Setting.getProviderTypeOptions("SAML").map((o) => {return {text: o.id, value: o.name};})}, {text: "SAML", value: "SAML", children: Setting.getProviderTypeOptions("SAML").map((o) => {return {text: o.id, value: o.name};})},
{text: "Captcha", value: "Captcha", children: Setting.getProviderTypeOptions("Captcha").map((o) => {return {text: o.id, value: o.name};})}, {text: "Captcha", value: "Captcha", children: Setting.getProviderTypeOptions("Captcha").map((o) => {return {text: o.id, value: o.name};})},
{text: "Payment", value: "Payment", children: Setting.getProviderTypeOptions("Payment").map((o) => {return {text: o.id, value: o.name};})},
], ],
sorter: true, sorter: true,
render: (text, record, index) => { render: (text, record, index) => {

View File

@ -17,7 +17,7 @@ import i18next from "i18next";
import React from "react"; import React from "react";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as UserBackend from "./backend/UserBackend"; import * as UserBackend from "./backend/UserBackend";
import {CountDownInput} from "./common/CountDownInput"; import {SendCodeInput} from "./common/SendCodeInput";
import {MailOutlined, PhoneOutlined} from "@ant-design/icons"; import {MailOutlined, PhoneOutlined} from "@ant-design/icons";
export const ResetModal = (props) => { export const ResetModal = (props) => {
@ -93,7 +93,7 @@ export const ResetModal = (props) => {
/> />
</Row> </Row>
<Row style={{width: "100%", marginBottom: "20px"}}> <Row style={{width: "100%", marginBottom: "20px"}}>
<CountDownInput <SendCodeInput
textBefore={i18next.t("code:Code You Received")} textBefore={i18next.t("code:Code You Received")}
onChange={setCode} onChange={setCode}
method={"reset"} method={"reset"}

View File

@ -18,6 +18,16 @@ import {Dropdown} from "antd";
import "./App.less"; import "./App.less";
import {GlobalOutlined} from "@ant-design/icons"; import {GlobalOutlined} from "@ant-design/icons";
export const Countries = [{label: "English", key: "en", country: "US", alt: "English"},
{label: "简体中文", key: "zh", country: "CN", alt: "简体中文"},
{label: "Español", key: "es", country: "ES", alt: "Español"},
{label: "Français", key: "fr", country: "FR", alt: "Français"},
{label: "Deutsch", key: "de", country: "DE", alt: "Deutsch"},
{label: "日本語", key: "ja", country: "JP", alt: "日本語"},
{label: "한국어", key: "ko", country: "KR", alt: "한국어"},
{label: "Русский", key: "ru", country: "RU", alt: "Русский"},
];
function flagIcon(country, alt) { function flagIcon(country, alt) {
return ( return (
<img width={24} alt={alt} src={`${Setting.StaticBaseUrl}/flag-icons/${country}.svg`} /> <img width={24} alt={alt} src={`${Setting.StaticBaseUrl}/flag-icons/${country}.svg`} />
@ -32,12 +42,12 @@ class SelectLanguageBox extends React.Component {
languages: props.languages ?? ["en", "zh", "es", "fr", "de", "ja", "ko", "ru"], languages: props.languages ?? ["en", "zh", "es", "fr", "de", "ja", "ko", "ru"],
}; };
Setting.Countries.forEach((country) => { Countries.forEach((country) => {
new Image().src = `${Setting.StaticBaseUrl}/flag-icons/${country.country}.svg`; new Image().src = `${Setting.StaticBaseUrl}/flag-icons/${country.country}.svg`;
}); });
} }
items = Setting.Countries.map((country) => Setting.getItem(country.label, country.key, flagIcon(country.country, country.alt))); items = Countries.map((country) => Setting.getItem(country.label, country.key, flagIcon(country.country, country.alt)));
getOrganizationLanguages(languages) { getOrganizationLanguages(languages) {
const select = []; const select = [];

View File

@ -49,8 +49,8 @@ class SelectRegionBox extends React.Component {
} }
> >
{ {
Setting.CountryRegionData.map((item, index) => ( Setting.getCountryNames().map((item) => (
<Option key={index} value={item.code} label={`${item.name} (${item.code})`} > <Option key={item.code} value={item.code} label={`${item.name} (${item.code})`} >
<img src={`${Setting.StaticBaseUrl}/flag-icons/${item.code}.svg`} alt={item.name} height={20} style={{marginRight: 10}} /> <img src={`${Setting.StaticBaseUrl}/flag-icons/${item.code}.svg`} alt={item.name} height={20} style={{marginRight: 10}} />
{`${item.name} (${item.code})`} {`${item.name} (${item.code})`}
</Option> </Option>

View File

@ -30,33 +30,13 @@ export const ServerUrl = "";
// export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static"; // export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static";
export const StaticBaseUrl = "https://cdn.casbin.org"; export const StaticBaseUrl = "https://cdn.casbin.org";
// https://catamphetamine.gitlab.io/country-flag-icons/3x2/index.html
export const CountryRegionData = getCountryRegionData();
export const Countries = [{label: "English", key: "en", country: "US", alt: "English"},
{label: "简体中文", key: "zh", country: "CN", alt: "简体中文"},
{label: "Español", key: "es", country: "ES", alt: "Español"},
{label: "Français", key: "fr", country: "FR", alt: "Français"},
{label: "Deutsch", key: "de", country: "DE", alt: "Deutsch"},
{label: "日本語", key: "ja", country: "JP", alt: "日本語"},
{label: "한국어", key: "ko", country: "KR", alt: "한국어"},
{label: "Русский", key: "ru", country: "RU", alt: "Русский"},
];
export const ThemeDefault = {
themeType: "default",
colorPrimary: "#5734d3",
borderRadius: 6,
isCompact: false,
};
export function getThemeData(organization, application) { export function getThemeData(organization, application) {
if (application?.themeData?.isEnabled) { if (application?.themeData?.isEnabled) {
return application.themeData; return application.themeData;
} else if (organization?.themeData?.isEnabled) { } else if (organization?.themeData?.isEnabled) {
return organization.themeData; return organization.themeData;
} else { } else {
return ThemeDefault; return Conf.ThemeDefault;
} }
} }
@ -114,9 +94,17 @@ export const OtherProviderInfo = {
}, },
Email: { Email: {
"Default": { "Default": {
logo: `${StaticBaseUrl}/img/social_default.png`, logo: `${StaticBaseUrl}/img/email_default.png`,
url: "", url: "",
}, },
"SUBMAIL": {
logo: `${StaticBaseUrl}/img/social_submail.svg`,
url: "https://www.mysubmail.com",
},
"Mailtrap": {
logo: `${StaticBaseUrl}/img/email_mailtrap.png`,
url: "https://mailtrap.io",
},
}, },
Storage: { Storage: {
"Local File System": { "Local File System": {
@ -174,7 +162,7 @@ export const OtherProviderInfo = {
}, },
Captcha: { Captcha: {
"Default": { "Default": {
logo: `${StaticBaseUrl}/img/social_default.png`, logo: `${StaticBaseUrl}/img/captcha_default.png`,
url: "https://pkg.go.dev/github.com/dchest/captcha", url: "https://pkg.go.dev/github.com/dchest/captcha",
}, },
"reCAPTCHA": { "reCAPTCHA": {
@ -200,18 +188,18 @@ export const OtherProviderInfo = {
}, },
}; };
export function getCountryRegionData() { export function getCountriesData() {
let language = i18next.language;
if (language === null || language === "null") {
language = Conf.DefaultLanguage;
}
const countries = require("i18n-iso-countries"); const countries = require("i18n-iso-countries");
countries.registerLocale(require("i18n-iso-countries/langs/" + language + ".json")); countries.registerLocale(require("i18n-iso-countries/langs/" + getLanguage() + ".json"));
const data = countries.getNames(language, {select: "official"}); return countries;
const result = []; }
for (const i in data) {result.push({code: i, name: data[i]});}
return result; export function getCountryNames() {
const data = getCountriesData().getNames(getLanguage(), {select: "official"});
return Object.entries(data).map(items => {
return {code: items[0], name: items[1]};
});
} }
export function initServerUrl() { export function initServerUrl() {
@ -694,7 +682,7 @@ export function getLanguageText(text) {
} }
export function getLanguage() { export function getLanguage() {
return i18next.language; return i18next.language ?? Conf.DefaultLanguage;
} }
export function setLanguage(language) { export function setLanguage(language) {
@ -835,6 +823,7 @@ export function getProviderTypeOptions(category) {
[ [
{id: "Default", name: "Default"}, {id: "Default", name: "Default"},
{id: "SUBMAIL", name: "SUBMAIL"}, {id: "SUBMAIL", name: "SUBMAIL"},
{id: "Mailtrap", name: "Mailtrap"},
] ]
); );
} else if (category === "SMS") { } else if (category === "SMS") {

View File

@ -135,13 +135,6 @@ class UserListPage extends BaseListPage {
} }
renderTable(users) { renderTable(users) {
// transfer country code to name based on selected language
const countries = require("i18n-iso-countries");
countries.registerLocale(require("i18n-iso-countries/langs/" + i18next.language + ".json"));
for (const index in users) {
users[index].region = countries.getName(users[index].region, i18next.language, {select: "official"});
}
const columns = [ const columns = [
{ {
title: i18next.t("general:Organization"), title: i18next.t("general:Organization"),
@ -267,6 +260,9 @@ class UserListPage extends BaseListPage {
width: "140px", width: "140px",
sorter: true, sorter: true,
...this.getColumnSearchProps("region"), ...this.getColumnSearchProps("region"),
render: (text, record, index) => {
return Setting.getCountriesData().getName(record.region, Setting.getLanguage(), {select: "official"});
},
}, },
{ {
title: i18next.t("user:Tag"), title: i18next.t("user:Tag"),

View File

@ -40,7 +40,6 @@ class CasLogout extends React.Component {
if (res.status === "ok") { if (res.status === "ok") {
Setting.showMessage("success", "Logged out successfully"); Setting.showMessage("success", "Logged out successfully");
this.props.onUpdateAccount(null); this.props.onUpdateAccount(null);
this.onUpdateApplication(null);
const redirectUri = res.data2; const redirectUri = res.data2;
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") { if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri); Setting.goToLink(redirectUri);
@ -50,7 +49,6 @@ class CasLogout extends React.Component {
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`); Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
} }
} else { } else {
this.onUpdateApplication(null);
Setting.showMessage("error", `Failed to log out: ${res.msg}`); Setting.showMessage("error", `Failed to log out: ${res.msg}`);
} }
}); });

View File

@ -19,7 +19,7 @@ import * as ApplicationBackend from "../backend/ApplicationBackend";
import * as Util from "./Util"; import * as Util from "./Util";
import * as Setting from "../Setting"; import * as Setting from "../Setting";
import i18next from "i18next"; import i18next from "i18next";
import {CountDownInput} from "../common/CountDownInput"; import {SendCodeInput} from "../common/SendCodeInput";
import * as UserBackend from "../backend/UserBackend"; import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons"; import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
@ -350,14 +350,14 @@ class ForgetPage extends React.Component {
]} ]}
> >
{this.state.verifyType === "email" ? ( {this.state.verifyType === "email" ? (
<CountDownInput <SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""} disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"} method={"forget"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]} onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
application={application} application={application}
/> />
) : ( ) : (
<CountDownInput <SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""} disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"} method={"forget"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.getApplicationObj()), this.state.name]} onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}

View File

@ -26,7 +26,7 @@ import * as Setting from "../Setting";
import SelfLoginButton from "./SelfLoginButton"; import SelfLoginButton from "./SelfLoginButton";
import i18next from "i18next"; import i18next from "i18next";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput"; import {SendCodeInput} from "../common/SendCodeInput";
import SelectLanguageBox from "../SelectLanguageBox"; import SelectLanguageBox from "../SelectLanguageBox";
import {CaptchaModal} from "../common/CaptchaModal"; import {CaptchaModal} from "../common/CaptchaModal";
import RedirectForm from "../common/RedirectForm"; import RedirectForm from "../common/RedirectForm";
@ -419,7 +419,7 @@ class LoginPage extends React.Component {
rules={[ rules={[
{ {
required: true, required: true,
message: i18next.t("login:Please input your username, Email or phone!"), message: i18next.t("login:Please input your Email or Phone!"),
}, },
{ {
validator: (_, value) => { validator: (_, value) => {
@ -755,7 +755,7 @@ class LoginPage extends React.Component {
name="code" name="code"
rules={[{required: true, message: i18next.t("login:Please input your code!")}]} rules={[{required: true, message: i18next.t("login:Please input your code!")}]}
> >
<CountDownInput <SendCodeInput
disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone} disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone}
method={"login"} method={"login"}
onButtonClickArgs={[this.state.username, this.state.validEmail ? "email" : "phone", Setting.getApplicationName(application)]} onButtonClickArgs={[this.state.username, this.state.validEmail ? "email" : "phone", Setting.getApplicationName(application)]}

View File

@ -21,7 +21,7 @@ import i18next from "i18next";
import * as Util from "./Util"; import * as Util from "./Util";
import {authConfig} from "./Auth"; import {authConfig} from "./Auth";
import * as ApplicationBackend from "../backend/ApplicationBackend"; import * as ApplicationBackend from "../backend/ApplicationBackend";
import {CountDownInput} from "../common/CountDownInput"; import {SendCodeInput} from "../common/SendCodeInput";
import SelectRegionBox from "../SelectRegionBox"; import SelectRegionBox from "../SelectRegionBox";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import SelectLanguageBox from "../SelectLanguageBox"; import SelectLanguageBox from "../SelectLanguageBox";
@ -365,7 +365,7 @@ class SignupPage extends React.Component {
message: i18next.t("code:Please input your verification code!"), message: i18next.t("code:Please input your verification code!"),
}]} }]}
> >
<CountDownInput <SendCodeInput
disabled={!this.state.validEmail} disabled={!this.state.validEmail}
method={"signup"} method={"signup"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]} onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]}
@ -419,7 +419,7 @@ class SignupPage extends React.Component {
}, },
]} ]}
> >
<CountDownInput <SendCodeInput
disabled={!this.state.validPhone} disabled={!this.state.validPhone}
method={"signup"} method={"signup"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]} onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}

View File

@ -109,7 +109,7 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
}).then(res => res.json()); }).then(res => res.json());
} }
export function sendCode(checkType, checkId, checkKey, method, dest, type, applicationId, checkUser) { export function sendCode(checkType, checkId, checkKey, method, dest, type, applicationId, checkUser = "") {
const formData = new FormData(); const formData = new FormData();
formData.append("checkType", checkType); formData.append("checkType", checkType);
formData.append("checkId", checkId); formData.append("checkId", checkId);

View File

@ -21,7 +21,7 @@ import {CaptchaWidget} from "./CaptchaWidget";
const {Search} = Input; const {Search} = Input;
export const CountDownInput = (props) => { export const SendCodeInput = (props) => {
const {disabled, textBefore, onChange, onButtonClickArgs, application, method} = props; const {disabled, textBefore, onChange, onButtonClickArgs, application, method} = props;
const [visible, setVisible] = React.useState(false); const [visible, setVisible] = React.useState(false);
const [key, setKey] = React.useState(""); const [key, setKey] = React.useState("");

View File

@ -14,14 +14,13 @@
import {Card, ConfigProvider, Form, Layout, Switch, theme} from "antd"; import {Card, ConfigProvider, Form, Layout, Switch, theme} from "antd";
import ThemePicker from "./ThemePicker"; import ThemePicker from "./ThemePicker";
import ColorPicker from "./ColorPicker"; import ColorPicker, {GREEN_COLOR, PINK_COLOR} from "./ColorPicker";
import RadiusPicker from "./RadiusPicker"; import RadiusPicker from "./RadiusPicker";
import * as React from "react"; import * as React from "react";
import {GREEN_COLOR, PINK_COLOR} from "./ColorPicker"; import {useEffect} from "react";
import {Content} from "antd/es/layout/layout"; import {Content} from "antd/es/layout/layout";
import i18next from "i18next"; import i18next from "i18next";
import {useEffect} from "react"; import * as Conf from "../../Conf";
import * as Setting from "../../Setting";
const ThemesInfo = { const ThemesInfo = {
default: {}, default: {},
@ -41,7 +40,7 @@ const ThemesInfo = {
const onChange = () => {}; const onChange = () => {};
export default function ThemeEditor(props) { export default function ThemeEditor(props) {
const themeData = props.themeData ?? Setting.ThemeDefault; const themeData = props.themeData ?? Conf.ThemeDefault;
const onThemeChange = props.onThemeChange ?? onChange; const onThemeChange = props.onThemeChange ?? onChange;
const {isCompact, themeType, ...themeToken} = themeData; const {isCompact, themeType, ...themeToken} = themeData;
@ -59,7 +58,7 @@ export default function ThemeEditor(props) {
}, [isLight, isCompact]); }, [isLight, isCompact]);
useEffect(() => { useEffect(() => {
const mergedData = Object.assign(Object.assign(Object.assign({}, Setting.ThemeDefault), {themeType}), ThemesInfo[themeType]); const mergedData = Object.assign(Object.assign(Object.assign({}, Conf.ThemeDefault), {themeType}), ThemesInfo[themeType]);
onThemeChange(null, mergedData); onThemeChange(null, mergedData);
form.setFieldsValue(mergedData); form.setFieldsValue(mergedData);
}, [themeType]); }, [themeType]);