Compare commits

...

19 Commits

Author SHA1 Message Date
14fa914e6f feat: add IsDemoMode for frontend (#1555)
* feat: add `IsDemoMode` for frontend

* fix: add i18n

* fix: support autologin and go same page

* fix: use i18n for button text
2023-02-16 20:36:30 +08:00
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
89 changed files with 1239 additions and 417 deletions

View File

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

View File

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

View File

@ -254,7 +254,10 @@ func (c *ApiController) Logout() {
if accessToken == "" && redirectUri == "" {
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)
application := c.GetSessionApplication()
@ -291,7 +294,8 @@ func (c *ApiController) Logout() {
}
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)
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
// @Tag Application API
// @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
// @router /get-application [get]
func (c *ApiController) GetApplication() {
@ -78,7 +78,7 @@ func (c *ApiController) GetApplication() {
// @Title GetUserApplication
// @Tag Application API
// @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
// @router /get-user-application [get]
func (c *ApiController) GetUserApplication() {
@ -134,7 +134,7 @@ func (c *ApiController) GetOrganizationApplications() {
// @Title UpdateApplication
// @Tag Application API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-application [post]

View File

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

View File

@ -18,9 +18,9 @@ import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
)
func (c *ApiController) GetCasbinAdapters() {

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetCerts() {
// @Title GetCert
// @Tag Cert API
// @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
// @router /get-cert [get]
func (c *ApiController) GetCert() {
@ -66,7 +66,7 @@ func (c *ApiController) GetCert() {
// @Title UpdateCert
// @Tag Cert API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-cert [post]

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetModels() {
// @Title GetModel
// @Tag Model API
// @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
// @router /get-model [get]
func (c *ApiController) GetModel() {
@ -66,7 +66,7 @@ func (c *ApiController) GetModel() {
// @Title UpdateModel
// @Tag Model API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-model [post]

View File

@ -66,7 +66,7 @@ func (c *ApiController) GetOrganization() {
// @Title UpdateOrganization
// @Tag Organization API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-organization [post]

View File

@ -71,7 +71,7 @@ func (c *ApiController) GetUserPayments() {
// @Title GetPayment
// @Tag Payment API
// @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
// @router /get-payment [get]
func (c *ApiController) GetPayment() {
@ -85,7 +85,7 @@ func (c *ApiController) GetPayment() {
// @Title UpdatePayment
// @Tag Payment API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-payment [post]
@ -172,7 +172,7 @@ func (c *ApiController) NotifyPayment() {
// @Title InvoicePayment
// @Tag Payment API
// @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
// @router /invoice-payment [post]
func (c *ApiController) InvoicePayment() {

View File

@ -69,7 +69,7 @@ func (c *ApiController) GetPermissionsBySubmitter() {
// @Title GetPermissionsByRole
// @Tag Permission API
// @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
// @router /get-permissions-by-role [get]
func (c *ApiController) GetPermissionsByRole() {
@ -83,7 +83,7 @@ func (c *ApiController) GetPermissionsByRole() {
// @Title GetPermission
// @Tag Permission API
// @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
// @router /get-permission [get]
func (c *ApiController) GetPermission() {
@ -97,7 +97,7 @@ func (c *ApiController) GetPermission() {
// @Title UpdatePermission
// @Tag Permission API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-permission [post]

View File

@ -53,7 +53,7 @@ func (c *ApiController) GetProducts() {
// @Title GetProduct
// @Tag Product API
// @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
// @router /get-product [get]
func (c *ApiController) GetProduct() {
@ -70,7 +70,7 @@ func (c *ApiController) GetProduct() {
// @Title UpdateProduct
// @Tag Product API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-product [post]
@ -130,7 +130,7 @@ func (c *ApiController) DeleteProduct() {
// @Title BuyProduct
// @Tag Product API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /buy-product [post]

View File

@ -76,7 +76,7 @@ func (c *ApiController) GetGlobalProviders() {
// @Title GetProvider
// @Tag Provider API
// @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
// @router /get-provider [get]
func (c *ApiController) GetProvider() {
@ -89,7 +89,7 @@ func (c *ApiController) GetProvider() {
// @Title UpdateProvider
// @Tag Provider API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-provider [post]

View File

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

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetRoles() {
// @Title GetRole
// @Tag Role API
// @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
// @router /get-role [get]
func (c *ApiController) GetRole() {
@ -66,7 +66,7 @@ func (c *ApiController) GetRole() {
// @Title UpdateRole
// @Tag Role API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-role [post]

View File

@ -22,29 +22,10 @@ import (
"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
// @Title GetSessions
// @Tag Session API
// @Description Get organization user sessions
// @Description Get organization user sessions.
// @Param owner query string true "The organization name"
// @Success 200 {array} string The Response object
// @router /get-sessions [get]
@ -66,3 +47,93 @@ func (c *ApiController) GetSessions() {
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
// @Tag Syncer API
// @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
// @router /get-syncer [get]
func (c *ApiController) GetSyncer() {
@ -66,7 +66,7 @@ func (c *ApiController) GetSyncer() {
// @Title UpdateSyncer
// @Tag Syncer API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-syncer [post]

View File

@ -29,7 +29,7 @@ type SystemInfo struct {
// @Title GetSystemInfo
// @Tag System API
// @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
// @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() {

View File

@ -54,7 +54,7 @@ func (c *ApiController) GetTokens() {
// @Title GetToken
// @Tag Token API
// @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
// @router /get-token [get]
func (c *ApiController) GetToken() {
@ -68,7 +68,7 @@ func (c *ApiController) GetToken() {
// @Title UpdateToken
// @Tag Token API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-token [post]
@ -128,7 +128,7 @@ func (c *ApiController) DeleteToken() {
// @Title GetOAuthCode
// @Tag Token API
// @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 response_type query string true "OAuth response type"
// @Param redirect_uri query string true "OAuth redirect URI"
@ -172,6 +172,7 @@ func (c *ApiController) GetOAuthCode() {
// @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret")
code := c.Input().Get("code")
@ -192,6 +193,7 @@ func (c *ApiController) GetOAuthToken() {
clientId = tokenRequest.ClientId
clientSecret = tokenRequest.ClientSecret
grantType = tokenRequest.GrantType
refreshToken = tokenRequest.RefreshToken
code = tokenRequest.Code
verifier = tokenRequest.Verifier
scope = tokenRequest.Scope
@ -203,7 +205,7 @@ func (c *ApiController) GetOAuthToken() {
}
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.ServeJSON()
}

View File

@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
// @Title GetUser
// @Tag User API
// @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 email query string false "The email of the user"
// @Param phone query string false "The phone of the user"
@ -129,7 +129,7 @@ func (c *ApiController) GetUser() {
// @Title UpdateUser
// @Tag User API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-user [post]

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetWebhooks() {
// @Title GetWebhook
// @Tag Webhook API
// @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
// @router /get-webhook [get]
func (c *ApiController) GetWebhook() {
@ -66,7 +66,7 @@ func (c *ApiController) GetWebhook() {
// @Title UpdateWebhook
// @Tag Webhook API
// @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"
// @Success 200 {object} controllers.Response The Response object
// @router /update-webhook [post]

11
go.mod
View File

@ -9,14 +9,14 @@ require (
github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0
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/gomail/v2 v2.0.1
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/denisenkom/go-mssqldb v0.9.0
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
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-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0
@ -41,18 +41,15 @@ require (
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
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
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
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/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.3.0 // indirect
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.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
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/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU=
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/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/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/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
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.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
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/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/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/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
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/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/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/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
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/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-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.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
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/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
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/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
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/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
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 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
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.27/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.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
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-20180826012351-8a410e7b638d/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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
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")
flag.Parse()
object.InitAdapter(*createDatabase)
object.InitAdapter()
object.DoMigration()
object.CreateTables(*createDatabase)
object.InitDb()
object.InitFromFile()
object.InitDefaultStorageProvider()

View File

@ -19,16 +19,15 @@ import (
"runtime"
"github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
_ "modernc.org/sqlite" // db = sqlite
"xorm.io/core"
"xorm.io/xorm"
"xorm.io/xorm/migrate"
"github.com/xorm-io/core"
"github.com/xorm-io/xorm"
_ "modernc.org/sqlite" // db = sqlite
)
var adapter *Adapter
@ -41,12 +40,16 @@ func InitConfig() {
beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true)
initMigrations()
InitAdapter()
DoMigration()
CreateTables(true)
}
func InitAdapter(createDatabase bool) {
func InitAdapter() {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
}
func CreateTables(createDatabase bool) {
if createDatabase {
adapter.CreateDatabase()
}
@ -252,22 +255,3 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
}
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/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type SignupItem struct {

View File

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

View File

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

View File

@ -19,7 +19,7 @@ package object
import (
"crypto/tls"
"github.com/go-gomail/gomail"
"github.com/casdoor/gomail/v2"
)
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.SetBody("text/html", content)
if provider.Type == "Mailtrap" {
message.SkipUsernameCheck = true
}
return dialer.DialAndSend(message)
}

View File

@ -25,8 +25,6 @@ import (
)
func InitDb() {
MigratePermissionRule()
existed := initBuiltInOrganization()
if !existed {
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/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type Model struct {

View File

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

View File

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

View File

@ -16,10 +16,9 @@ package object
import (
"fmt"
"strings"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type Permission struct {
@ -269,33 +268,6 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
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 {
containsAsterisk := false
group, _ := util.GetOwnerAndNameFromId(userId)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,84 +15,27 @@
package object
import (
"fmt"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
var (
CasdoorApplication = "app-built-in"
CasdoorOrganization = "built-in"
)
type Session struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
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"`
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 {
sessions := []*Session{}
var err error
@ -128,3 +71,131 @@ func GetSessionCount(owner, field, value string) int {
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"
"fmt"
"net/url"
"path/filepath"
"strings"
"github.com/casdoor/casdoor/conf"
@ -54,6 +55,25 @@ func escapePath(path string) string {
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) {
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn"
"xorm.io/core"
"github.com/xorm-io/core"
)
const (
@ -578,7 +578,7 @@ func AddUsersInBatch(users []*User) bool {
func DeleteUser(user *User) bool {
// 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{})
if err != nil {

View File

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

View File

@ -20,7 +20,7 @@ import (
"strings"
"github.com/casdoor/casdoor/idp"
"xorm.io/core"
"github.com/xorm-io/core"
)
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/i18n"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
const (

View File

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

View File

@ -57,7 +57,7 @@ func AutoSigninFilter(ctx *context.Context) {
return
}
// "/page?username=abc&password=123"
// "/page?username=built-in/admin&password=123"
userId = ctx.Input.Query("username")
password := ctx.Input.Query("password")
if userId != "" && password != "" && ctx.Input.Query("grant_type") == "" {

View File

@ -163,7 +163,11 @@ func initAPI() {
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
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/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")

View File

@ -578,7 +578,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
},
@ -894,8 +894,8 @@
"parameters": [
{
"in": "query",
"name": "ID",
"description": "The ID(owner/name) of user.",
"name": "id",
"description": "The id ( owner/name )(owner/name) of user.",
"required": true,
"type": "string"
}
@ -1107,7 +1107,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the application.",
"description": "The id ( owner/name ) of the application.",
"required": true,
"type": "string"
}
@ -1162,7 +1162,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the cert",
"description": "The id ( owner/name ) of the cert",
"required": true,
"type": "string"
}
@ -1340,7 +1340,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the model",
"description": "The id ( owner/name ) of the model",
"required": true,
"type": "string"
}
@ -1479,7 +1479,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
}
@ -1534,7 +1534,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the permission",
"description": "The id ( owner/name ) of the permission",
"required": true,
"type": "string"
}
@ -1589,7 +1589,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
}
@ -1638,7 +1638,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
}
@ -1693,7 +1693,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the provider",
"description": "The id ( owner/name ) of the provider",
"required": true,
"type": "string"
}
@ -1840,7 +1840,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
}
@ -1966,7 +1966,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the syncer",
"description": "The id ( owner/name ) of the syncer",
"required": true,
"type": "string"
}
@ -2021,7 +2021,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
}
@ -2047,7 +2047,7 @@
{
"in": "query",
"name": "id",
"description": "The id of token",
"description": "The id ( owner/name ) of token",
"required": true,
"type": "string"
}
@ -2116,7 +2116,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
},
@ -2160,7 +2160,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
}
@ -2286,7 +2286,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the webhook",
"description": "The id ( owner/name ) of the webhook",
"required": true,
"type": "string"
}
@ -2341,7 +2341,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
}
@ -2504,8 +2504,8 @@
"parameters": [
{
"in": "query",
"name": "user_id",
"description": "The id of user",
"name": "id",
"description": "The id ( owner/name ) of user",
"required": true,
"type": "string"
},
@ -2904,7 +2904,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the application",
"description": "The id ( owner/name ) of the application",
"required": true,
"type": "string"
},
@ -2939,7 +2939,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the cert",
"description": "The id ( owner/name ) of the cert",
"required": true,
"type": "string"
},
@ -2982,7 +2982,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the model",
"description": "The id ( owner/name ) of the model",
"required": true,
"type": "string"
},
@ -3017,7 +3017,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the organization",
"description": "The id ( owner/name ) of the organization",
"required": true,
"type": "string"
},
@ -3052,7 +3052,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
},
@ -3087,7 +3087,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the permission",
"description": "The id ( owner/name ) of the permission",
"required": true,
"type": "string"
},
@ -3122,7 +3122,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
},
@ -3157,7 +3157,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the provider",
"description": "The id ( owner/name ) of the provider",
"required": true,
"type": "string"
},
@ -3200,7 +3200,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
},
@ -3235,7 +3235,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the syncer",
"description": "The id ( owner/name ) of the syncer",
"required": true,
"type": "string"
},
@ -3270,7 +3270,7 @@
{
"in": "query",
"name": "id",
"description": "The id of token",
"description": "The id ( owner/name ) of token",
"required": true,
"type": "string"
},
@ -3305,7 +3305,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
},
@ -3340,7 +3340,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the webhook",
"description": "The id ( owner/name ) of the webhook",
"required": true,
"type": "string"
},
@ -3505,11 +3505,11 @@
}
},
"definitions": {
"2268.0xc0000f9650.false": {
"2346.0xc0001ce990.false": {
"title": "false",
"type": "object"
},
"2302.0xc0000f9680.false": {
"2381.0xc0001ce9c0.false": {
"title": "false",
"type": "object"
},
@ -3636,10 +3636,10 @@
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/2268.0xc0000f9650.false"
"$ref": "#/definitions/2346.0xc0001ce990.false"
},
"data2": {
"$ref": "#/definitions/2302.0xc0000f9680.false"
"$ref": "#/definitions/2381.0xc0001ce9c0.false"
},
"msg": {
"type": "string"
@ -3846,6 +3846,9 @@
"termsOfUse": {
"type": "string"
},
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"tokenFormat": {
"type": "string"
}
@ -4143,6 +4146,9 @@
"type": "string"
}
},
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"websiteUrl": {
"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": {
"title": "Token",
"type": "object",
@ -4836,9 +4864,15 @@
"alipay": {
"type": "string"
},
"amazon": {
"type": "string"
},
"apple": {
"type": "string"
},
"auth0": {
"type": "string"
},
"avatar": {
"type": "string"
},
@ -4848,6 +4882,9 @@
"baidu": {
"type": "string"
},
"battlenet": {
"type": "string"
},
"bilibili": {
"type": "string"
},
@ -4857,9 +4894,18 @@
"birthday": {
"type": "string"
},
"bitbucket": {
"type": "string"
},
"box": {
"type": "string"
},
"casdoor": {
"type": "string"
},
"cloudfoundry": {
"type": "string"
},
"createdIp": {
"type": "string"
},
@ -4869,15 +4915,30 @@
"custom": {
"type": "string"
},
"dailymotion": {
"type": "string"
},
"deezer": {
"type": "string"
},
"digitalocean": {
"type": "string"
},
"dingtalk": {
"type": "string"
},
"discord": {
"type": "string"
},
"displayName": {
"type": "string"
},
"douyin": {
"type": "string"
},
"dropbox": {
"type": "string"
},
"education": {
"type": "string"
},
@ -4887,15 +4948,24 @@
"emailVerified": {
"type": "boolean"
},
"eveonline": {
"type": "string"
},
"facebook": {
"type": "string"
},
"firstName": {
"type": "string"
},
"fitbit": {
"type": "string"
},
"gender": {
"type": "string"
},
"gitea": {
"type": "string"
},
"gitee": {
"type": "string"
},
@ -4911,6 +4981,9 @@
"hash": {
"type": "string"
},
"heroku": {
"type": "string"
},
"homepage": {
"type": "string"
},
@ -4923,9 +4996,18 @@
"idCardType": {
"type": "string"
},
"influxcloud": {
"type": "string"
},
"infoflow": {
"type": "string"
},
"instagram": {
"type": "string"
},
"intercom": {
"type": "string"
},
"isAdmin": {
"type": "boolean"
},
@ -4944,6 +5026,9 @@
"isOnline": {
"type": "boolean"
},
"kakao": {
"type": "string"
},
"karma": {
"type": "integer",
"format": "int64"
@ -4966,6 +5051,9 @@
"lastSigninWrongTime": {
"type": "string"
},
"lastfm": {
"type": "string"
},
"ldap": {
"type": "string"
},
@ -4978,18 +5066,39 @@
"location": {
"type": "string"
},
"mailru": {
"type": "string"
},
"managedAccounts": {
"type": "array",
"items": {
"$ref": "#/definitions/object.ManagedAccount"
}
},
"meetup": {
"type": "string"
},
"microsoftonline": {
"type": "string"
},
"name": {
"type": "string"
},
"naver": {
"type": "string"
},
"nextcloud": {
"type": "string"
},
"okta": {
"type": "string"
},
"onedrive": {
"type": "string"
},
"oura": {
"type": "string"
},
"owner": {
"type": "string"
},
@ -4999,6 +5108,12 @@
"passwordSalt": {
"type": "string"
},
"patreon": {
"type": "string"
},
"paypal": {
"type": "string"
},
"permanentAvatar": {
"type": "string"
},
@ -5035,10 +5150,16 @@
"$ref": "#/definitions/object.Role"
}
},
"salesforce": {
"type": "string"
},
"score": {
"type": "integer",
"format": "int64"
},
"shopify": {
"type": "string"
},
"signinWrongTimes": {
"type": "integer",
"format": "int64"
@ -5049,21 +5170,54 @@
"slack": {
"type": "string"
},
"soundcloud": {
"type": "string"
},
"spotify": {
"type": "string"
},
"steam": {
"type": "string"
},
"strava": {
"type": "string"
},
"stripe": {
"type": "string"
},
"tag": {
"type": "string"
},
"tiktok": {
"type": "string"
},
"title": {
"type": "string"
},
"tumblr": {
"type": "string"
},
"twitch": {
"type": "string"
},
"twitter": {
"type": "string"
},
"type": {
"type": "string"
},
"typetalk": {
"type": "string"
},
"uber": {
"type": "string"
},
"updatedTime": {
"type": "string"
},
"vk": {
"type": "string"
},
"webauthnCredentials": {
"type": "array",
"items": {
@ -5078,6 +5232,24 @@
},
"weibo": {
"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:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
- in: query
@ -578,8 +578,8 @@ paths:
operationId: ApiController.DeleteSession
parameters:
- in: query
name: ID
description: The ID(owner/name) of user.
name: id
description: The id ( owner/name )(owner/name) of user.
required: true
type: string
responses:
@ -718,7 +718,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the application.
description: The id ( owner/name ) of the application.
required: true
type: string
responses:
@ -754,7 +754,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the cert
description: The id ( owner/name ) of the cert
required: true
type: string
responses:
@ -870,7 +870,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the model
description: The id ( owner/name ) of the model
required: true
type: string
responses:
@ -961,7 +961,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
responses:
@ -997,7 +997,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the permission
description: The id ( owner/name ) of the permission
required: true
type: string
responses:
@ -1033,7 +1033,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
responses:
@ -1065,7 +1065,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
responses:
@ -1101,7 +1101,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the provider
description: The id ( owner/name ) of the provider
required: true
type: string
responses:
@ -1197,7 +1197,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
responses:
@ -1280,7 +1280,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the syncer
description: The id ( owner/name ) of the syncer
required: true
type: string
responses:
@ -1316,7 +1316,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
responses:
@ -1333,7 +1333,7 @@ paths:
parameters:
- in: query
name: id
description: The id of token
description: The id ( owner/name ) of token
required: true
type: string
responses:
@ -1379,7 +1379,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
- in: query
@ -1408,7 +1408,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
responses:
@ -1491,7 +1491,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the webhook
description: The id ( owner/name ) of the webhook
required: true
type: string
responses:
@ -1527,7 +1527,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
responses:
@ -1636,8 +1636,8 @@ paths:
operationId: ApiController.GetOAuthCode
parameters:
- in: query
name: user_id
description: The id of user
name: id
description: The id ( owner/name ) of user
required: true
type: string
- in: query
@ -1902,7 +1902,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the application
description: The id ( owner/name ) of the application
required: true
type: string
- in: body
@ -1925,7 +1925,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the cert
description: The id ( owner/name ) of the cert
required: true
type: string
- in: body
@ -1953,7 +1953,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the model
description: The id ( owner/name ) of the model
required: true
type: string
- in: body
@ -1976,7 +1976,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the organization
description: The id ( owner/name ) of the organization
required: true
type: string
- in: body
@ -1999,7 +1999,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
- in: body
@ -2022,7 +2022,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the permission
description: The id ( owner/name ) of the permission
required: true
type: string
- in: body
@ -2045,7 +2045,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
- in: body
@ -2068,7 +2068,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the provider
description: The id ( owner/name ) of the provider
required: true
type: string
- in: body
@ -2096,7 +2096,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
- in: body
@ -2119,7 +2119,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the syncer
description: The id ( owner/name ) of the syncer
required: true
type: string
- in: body
@ -2142,7 +2142,7 @@ paths:
parameters:
- in: query
name: id
description: The id of token
description: The id ( owner/name ) of token
required: true
type: string
- in: body
@ -2165,7 +2165,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
- in: body
@ -2188,7 +2188,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the webhook
description: The id ( owner/name ) of the webhook
required: true
type: string
- in: body
@ -2293,10 +2293,10 @@ paths:
schema:
$ref: '#/definitions/Response'
definitions:
2268.0xc0000f9650.false:
2346.0xc0001ce990.false:
title: "false"
type: object
2302.0xc0000f9680.false:
2381.0xc0001ce9c0.false:
title: "false"
type: object
Response:
@ -2383,9 +2383,9 @@ definitions:
type: object
properties:
data:
$ref: '#/definitions/2268.0xc0000f9650.false'
$ref: '#/definitions/2346.0xc0001ce990.false'
data2:
$ref: '#/definitions/2302.0xc0000f9680.false'
$ref: '#/definitions/2381.0xc0001ce9c0.false'
msg:
type: string
name:
@ -2524,6 +2524,8 @@ definitions:
type: string
termsOfUse:
type: string
themeData:
$ref: '#/definitions/object.ThemeData'
tokenFormat:
type: string
object.Cert:
@ -2724,6 +2726,8 @@ definitions:
type: array
items:
type: string
themeData:
$ref: '#/definitions/object.ThemeData'
websiteUrl:
type: string
object.Payment:
@ -3115,6 +3119,21 @@ definitions:
type: array
items:
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:
title: Token
type: object
@ -3190,46 +3209,74 @@ definitions:
type: string
alipay:
type: string
amazon:
type: string
apple:
type: string
auth0:
type: string
avatar:
type: string
azuread:
type: string
baidu:
type: string
battlenet:
type: string
bilibili:
type: string
bio:
type: string
birthday:
type: string
bitbucket:
type: string
box:
type: string
casdoor:
type: string
cloudfoundry:
type: string
createdIp:
type: string
createdTime:
type: string
custom:
type: string
dailymotion:
type: string
deezer:
type: string
digitalocean:
type: string
dingtalk:
type: string
discord:
type: string
displayName:
type: string
douyin:
type: string
dropbox:
type: string
education:
type: string
email:
type: string
emailVerified:
type: boolean
eveonline:
type: string
facebook:
type: string
firstName:
type: string
fitbit:
type: string
gender:
type: string
gitea:
type: string
gitee:
type: string
github:
@ -3240,6 +3287,8 @@ definitions:
type: string
hash:
type: string
heroku:
type: string
homepage:
type: string
id:
@ -3248,8 +3297,14 @@ definitions:
type: string
idCardType:
type: string
influxcloud:
type: string
infoflow:
type: string
instagram:
type: string
intercom:
type: string
isAdmin:
type: boolean
isDefaultAvatar:
@ -3262,6 +3317,8 @@ definitions:
type: boolean
isOnline:
type: boolean
kakao:
type: string
karma:
type: integer
format: int64
@ -3277,6 +3334,8 @@ definitions:
type: string
lastSigninWrongTime:
type: string
lastfm:
type: string
ldap:
type: string
line:
@ -3285,20 +3344,38 @@ definitions:
type: string
location:
type: string
mailru:
type: string
managedAccounts:
type: array
items:
$ref: '#/definitions/object.ManagedAccount'
meetup:
type: string
microsoftonline:
type: string
name:
type: string
naver:
type: string
nextcloud:
type: string
okta:
type: string
onedrive:
type: string
oura:
type: string
owner:
type: string
password:
type: string
passwordSalt:
type: string
patreon:
type: string
paypal:
type: string
permanentAvatar:
type: string
permissions:
@ -3323,9 +3400,13 @@ definitions:
type: array
items:
$ref: '#/definitions/object.Role'
salesforce:
type: string
score:
type: integer
format: int64
shopify:
type: string
signinWrongTimes:
type: integer
format: int64
@ -3333,16 +3414,38 @@ definitions:
type: string
slack:
type: string
soundcloud:
type: string
spotify:
type: string
steam:
type: string
strava:
type: string
stripe:
type: string
tag:
type: string
tiktok:
type: string
title:
type: string
tumblr:
type: string
twitch:
type: string
twitter:
type: string
type:
type: string
typetalk:
type: string
uber:
type: string
updatedTime:
type: string
vk:
type: string
webauthnCredentials:
type: array
items:
@ -3353,6 +3456,18 @@ definitions:
type: string
weibo:
type: string
wepay:
type: string
xero:
type: string
yahoo:
type: string
yammer:
type: string
yandex:
type: string
zoom:
type: string
object.Userinfo:
title: Userinfo
type: object

View File

@ -100,6 +100,15 @@ func GetOwnerAndNameFromIdNoCheck(id string) (string, string) {
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 {
return uuid.NewString()
}
@ -127,6 +136,10 @@ func GetId(owner, name string) string {
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 {
hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:])

View File

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

View File

@ -31,6 +31,6 @@ func GetCurrentUnixTime() string {
func IsTokenExpired(createdTime string, expiresIn int) bool {
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)
}

View File

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

View File

@ -84,8 +84,8 @@ class App extends Component {
uri: null,
menuVisible: false,
themeAlgorithm: ["default"],
themeData: Setting.ThemeDefault,
logo: this.getLogo(Setting.getAlgorithmNames(Setting.ThemeDefault)),
themeData: Conf.ThemeDefault,
logo: this.getLogo(Setting.getAlgorithmNames(Conf.ThemeDefault)),
};
Setting.initServerUrl();
@ -554,6 +554,13 @@ class App extends Component {
};
renderContent() {
const onClick = ({key}) => {
if (key === "/swagger") {
window.open(Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger", "_blank");
} else {
this.props.history.push(key);
}
};
return (
<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*/}
@ -580,6 +587,7 @@ class App extends Component {
</Button>
</React.Fragment> :
<Menu
onClick={onClick}
items={this.getMenuItems()}
mode={"horizontal"}
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 CertBackend from "./backend/CertBackend";
import * as Setting from "./Setting";
import * as Conf from "./Conf";
import * as ProviderBackend from "./backend/ProviderBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ResourceBackend from "./backend/ResourceBackend";
@ -717,7 +718,7 @@ class ApplicationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}>
<Row>
<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});
}} >
<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 ?
<Row style={{marginTop: "20px"}}>
<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});
}} />
</Row> : null
@ -764,7 +765,7 @@ class ApplicationEditPage extends React.Component {
}
renderSignupSigninPreview() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault;
const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
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 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() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault;
const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
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)"};
return (

View File

@ -14,9 +14,17 @@
export const ShowGithubCorner = false;
export const GithubRepo = "https://github.com/casdoor/casdoor";
export const IsDemoMode = false;
export const ForceLanguage = "";
export const DefaultLanguage = "en";
export const InitThemeAlgorithm = 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 i18next from "i18next";
import * as Setting from "./Setting";
import * as Conf from "./Conf";
import SignupPage from "./auth/SignupPage";
import SelfLoginPage from "./auth/SelfLoginPage";
import LoginPage from "./auth/LoginPage";
@ -62,7 +63,7 @@ class EntryPage extends React.Component {
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);
};
@ -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="/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="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} {...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/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"} onUpdateApplication={onUpdateApplication} {...props} />);}} />
</Switch>
</div>
);

View File

@ -18,6 +18,7 @@ import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as LdapBackend from "./backend/LdapBackend";
import * as Setting from "./Setting";
import * as Conf from "./Conf";
import i18next from "i18next";
import {LinkOutlined} from "@ant-design/icons";
import LdapTable from "./LdapTable";
@ -324,7 +325,7 @@ class OrganizationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}>
<Row>
<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});
}} >
<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 ?
<Row style={{marginTop: "20px"}}>
<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});
}} />
</Row> : null

View File

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

View File

@ -18,6 +18,16 @@ import {Dropdown} from "antd";
import "./App.less";
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) {
return (
<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"],
};
Setting.Countries.forEach((country) => {
Countries.forEach((country) => {
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) {
const select = [];

View File

@ -49,8 +49,8 @@ class SelectRegionBox extends React.Component {
}
>
{
Setting.CountryRegionData.map((item, index) => (
<Option key={index} value={item.code} label={`${item.name} (${item.code})`} >
Setting.getCountryNames().map((item) => (
<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}} />
{`${item.name} (${item.code})`}
</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.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) {
if (application?.themeData?.isEnabled) {
return application.themeData;
} else if (organization?.themeData?.isEnabled) {
return organization.themeData;
} else {
return ThemeDefault;
return Conf.ThemeDefault;
}
}
@ -118,8 +98,12 @@ export const OtherProviderInfo = {
url: "",
},
"SUBMAIL": {
logo: `${StaticBaseUrl}/img/social_submail.png`,
url: "",
logo: `${StaticBaseUrl}/img/social_submail.svg`,
url: "https://www.mysubmail.com",
},
"Mailtrap": {
logo: `${StaticBaseUrl}/img/email_mailtrap.png`,
url: "https://mailtrap.io",
},
},
Storage: {
@ -204,18 +188,18 @@ export const OtherProviderInfo = {
},
};
export function getCountryRegionData() {
let language = i18next.language;
if (language === null || language === "null") {
language = Conf.DefaultLanguage;
}
export function getCountriesData() {
const countries = require("i18n-iso-countries");
countries.registerLocale(require("i18n-iso-countries/langs/" + language + ".json"));
const data = countries.getNames(language, {select: "official"});
const result = [];
for (const i in data) {result.push({code: i, name: data[i]});}
return result;
countries.registerLocale(require("i18n-iso-countries/langs/" + getLanguage() + ".json"));
return countries;
}
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() {
@ -698,7 +682,7 @@ export function getLanguageText(text) {
}
export function getLanguage() {
return i18next.language;
return i18next.language ?? Conf.DefaultLanguage;
}
export function setLanguage(language) {
@ -839,6 +823,7 @@ export function getProviderTypeOptions(category) {
[
{id: "Default", name: "Default"},
{id: "SUBMAIL", name: "SUBMAIL"},
{id: "Mailtrap", name: "Mailtrap"},
]
);
} else if (category === "SMS") {

View File

@ -135,13 +135,6 @@ class UserListPage extends BaseListPage {
}
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 = [
{
title: i18next.t("general:Organization"),
@ -267,6 +260,9 @@ class UserListPage extends BaseListPage {
width: "140px",
sorter: true,
...this.getColumnSearchProps("region"),
render: (text, record, index) => {
return Setting.getCountriesData().getName(record.region, Setting.getLanguage(), {select: "official"});
},
},
{
title: i18next.t("user:Tag"),

View File

@ -40,7 +40,6 @@ class CasLogout extends React.Component {
if (res.status === "ok") {
Setting.showMessage("success", "Logged out successfully");
this.props.onUpdateAccount(null);
this.onUpdateApplication(null);
const redirectUri = res.data2;
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri);
@ -50,7 +49,6 @@ class CasLogout extends React.Component {
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
}
} else {
this.onUpdateApplication(null);
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 Setting from "../Setting";
import i18next from "i18next";
import {CountDownInput} from "../common/CountDownInput";
import {SendCodeInput} from "../common/SendCodeInput";
import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../CustomGithubCorner";
@ -350,14 +350,14 @@ class ForgetPage extends React.Component {
]}
>
{this.state.verifyType === "email" ? (
<CountDownInput
<SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
application={application}
/>
) : (
<CountDownInput
<SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"}
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 i18next from "i18next";
import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput";
import {SendCodeInput} from "../common/SendCodeInput";
import SelectLanguageBox from "../SelectLanguageBox";
import {CaptchaModal} from "../common/CaptchaModal";
import RedirectForm from "../common/RedirectForm";
@ -419,7 +419,7 @@ class LoginPage extends React.Component {
rules={[
{
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) => {
@ -755,7 +755,7 @@ class LoginPage extends React.Component {
name="code"
rules={[{required: true, message: i18next.t("login:Please input your code!")}]}
>
<CountDownInput
<SendCodeInput
disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone}
method={"login"}
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 {authConfig} from "./Auth";
import * as ApplicationBackend from "../backend/ApplicationBackend";
import {CountDownInput} from "../common/CountDownInput";
import {SendCodeInput} from "../common/SendCodeInput";
import SelectRegionBox from "../SelectRegionBox";
import CustomGithubCorner from "../CustomGithubCorner";
import SelectLanguageBox from "../SelectLanguageBox";
@ -365,7 +365,7 @@ class SignupPage extends React.Component {
message: i18next.t("code:Please input your verification code!"),
}]}
>
<CountDownInput
<SendCodeInput
disabled={!this.state.validEmail}
method={"signup"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]}
@ -419,7 +419,7 @@ class SignupPage extends React.Component {
},
]}
>
<CountDownInput
<SendCodeInput
disabled={!this.state.validPhone}
method={"signup"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}

View File

@ -0,0 +1,63 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {ExclamationCircleFilled} from "@ant-design/icons";
import {Modal} from "antd";
import i18next from "i18next";
import * as Conf from "../Conf";
const {confirm} = Modal;
const {fetch: originalFetch} = window;
/**
* When modify data, prompt it's read-only and ask whether to go writable site
*/
const demoModePrompt = async(url, option) => {
if (option.method === "POST") {
confirm({
title: i18next.t("general:This is a read-only demo site!"),
icon: <ExclamationCircleFilled />,
content: i18next.t("general:Go Writable demo site?"),
okText: i18next.t("user:OK"),
cancelText: i18next.t("general:Cancel"),
onOk() {
const fullURL = document.location.toString();
window.open("https://demo.casdoor.com" + fullURL.substring(fullURL.lastIndexOf("/")) + "?username=built-in/admin&password=123", "_blank");
},
onCancel() {},
});
}
return option;
};
const requsetInterceptors = [];
const responseInterceptors = [];
// when it's in DemoMode, demoModePrompt() should run before fetch
if (Conf.IsDemoMode) {
requsetInterceptors.push(demoModePrompt);
}
/**
* rewrite fetch to support interceptors
*/
window.fetch = async(url, option = {}) => {
for (const fn of requsetInterceptors) {
fn(url, option);
}
const response = await originalFetch(url, option);
responseInterceptors.forEach(fn => (response) => fn(response));
return response;
};

View File

@ -109,7 +109,7 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
}).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();
formData.append("checkType", checkType);
formData.append("checkId", checkId);

View File

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

View File

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

View File

@ -22,6 +22,7 @@ import "./App.less";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import {BrowserRouter} from "react-router-dom";
import "./backend/FetchInterceptor";
const container = document.getElementById("root");

View File

@ -181,6 +181,7 @@
"First name": "First name",
"Forget URL": "URL vergessen",
"Forget URL - Tooltip": "Unique string-style identifier",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Zuhause",
"Home - Tooltip": "Application homepage",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Zeitstempel",
"Tokens": "Token",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "First name",
"Forget URL": "Forget URL",
"Forget URL - Tooltip": "Forget URL - Tooltip",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Home",
"Home - Tooltip": "Home - Tooltip",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "Nombre",
"Forget URL": "URL de olvido",
"Forget URL - Tooltip": "URL de olvido - Tooltip",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Inicio",
"Home - Tooltip": "Inicio - Tooltip",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sincronizador",
"Syncers": "Sincronizadores",
"SysInfo": "SysInfo",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "First name",
"Forget URL": "Oublier l'URL",
"Forget URL - Tooltip": "Unique string-style identifier",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Domicile",
"Home - Tooltip": "Application homepage",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Synchronisateurs",
"SysInfo": "SysInfo",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Horodatage",
"Tokens": "Jetons",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "First name",
"Forget URL": "URLを忘れた",
"Forget URL - Tooltip": "Unique string-style identifier",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "ホーム",
"Home - Tooltip": "Application homepage",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "システム情報",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "タイムスタンプ",
"Tokens": "トークン",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "First name",
"Forget URL": "Forget URL",
"Forget URL - Tooltip": "Unique string-style identifier",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Home",
"Home - Tooltip": "Application homepage",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "Имя",
"Forget URL": "Забыть URL",
"Forget URL - Tooltip": "Unique string-style identifier",
"Go Writable demo site?": "Go Writable demo site?",
"Home": "Домашний",
"Home - Tooltip": "Application homepage",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "Sync",
"Syncers": "Синхронизаторы",
"SysInfo": "Информация о системе",
"This is a read-only demo site!": "This is a read-only demo site!",
"Timestamp": "Отметка времени",
"Tokens": "Жетоны",
"URL": "URL",

View File

@ -181,6 +181,7 @@
"First name": "名字",
"Forget URL": "忘记密码URL",
"Forget URL - Tooltip": "忘记密码URL",
"Go Writable demo site?": "跳转至可写演示站点?",
"Home": "首页",
"Home - Tooltip": "应用的首页",
"ID": "ID",
@ -255,6 +256,7 @@
"Sync": "同步",
"Syncers": "同步器",
"SysInfo": "系统信息",
"This is a read-only demo site!": "这是一个只读演示站点!",
"Timestamp": "时间戳",
"Tokens": "令牌",
"URL": "链接",