mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-10 10:15:19 +08:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
b525210835 | |||
4ab2ca7a25 | |||
dcf148fb7f | |||
c8846f1a2d | |||
0559298d6c | |||
ddb5e26fcd | |||
1f39027b78 | |||
eae3b0d367 | |||
186f0ac97b | |||
308f305c53 | |||
d498bc60ce | |||
7bbe1e38c1 | |||
f465fc6ce0 | |||
c952c2f2f4 | |||
86ae97d1e5 |
5
.gitattributes
vendored
5
.gitattributes
vendored
@ -1,2 +1,5 @@
|
|||||||
*.go linguist-detectable=true
|
*.go linguist-detectable=true
|
||||||
*.js linguist-detectable=false
|
*.js linguist-detectable=false
|
||||||
|
# Declare files that will always have LF line endings on checkout.
|
||||||
|
# Git will always convert line endings to LF on checkout. You should use this for files that must keep LF endings, even on Windows.
|
||||||
|
*.sh text eol=lf
|
@ -242,6 +242,7 @@ func (c *ApiController) Signup() {
|
|||||||
// @router /logout [get,post]
|
// @router /logout [get,post]
|
||||||
func (c *ApiController) Logout() {
|
func (c *ApiController) Logout() {
|
||||||
user := c.GetSessionUsername()
|
user := c.GetSessionUsername()
|
||||||
|
object.DeleteSessionId(user, c.Ctx.Input.CruSession.SessionID())
|
||||||
util.LogInfo(c.Ctx, "API: [%s] logged out", user)
|
util.LogInfo(c.Ctx, "API: [%s] logged out", user)
|
||||||
|
|
||||||
application := c.GetSessionApplication()
|
application := c.GetSessionApplication()
|
||||||
@ -271,12 +272,17 @@ func (c *ApiController) GetAccount() {
|
|||||||
user = object.ExtendManagedAccountsWithUser(user)
|
user = object.ExtendManagedAccountsWithUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object.ExtendUserWithRolesAndPermissions(user)
|
||||||
|
|
||||||
|
user.Permissions = object.GetMaskedPermissions(user.Permissions)
|
||||||
|
user.Roles = object.GetMaskedRoles(user.Roles)
|
||||||
|
|
||||||
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
|
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
|
||||||
resp := Response{
|
resp := Response{
|
||||||
Status: "ok",
|
Status: "ok",
|
||||||
Sub: user.Id,
|
Sub: user.Id,
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
Data: user,
|
Data: object.GetMaskedUser(user),
|
||||||
Data2: organization,
|
Data2: organization,
|
||||||
}
|
}
|
||||||
c.Data["json"] = resp
|
c.Data["json"] = resp
|
||||||
|
@ -103,12 +103,12 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
resp = tokenToResponse(token)
|
resp = tokenToResponse(token)
|
||||||
}
|
}
|
||||||
} else if form.Type == ResponseTypeSaml { // saml flow
|
} else if form.Type == ResponseTypeSaml { // saml flow
|
||||||
res, redirectUrl, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
|
res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error(), nil)
|
c.ResponseError(err.Error(), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: redirectUrl}
|
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]string{"redirectUrl": redirectUrl, "method": method}}
|
||||||
} else if form.Type == ResponseTypeCas {
|
} else if form.Type == ResponseTypeCas {
|
||||||
// not oauth but CAS SSO protocol
|
// not oauth but CAS SSO protocol
|
||||||
service := c.Input().Get("service")
|
service := c.Input().Get("service")
|
||||||
@ -139,6 +139,10 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.Status == "ok" {
|
||||||
|
object.SetSession(user.GetId(), c.Ctx.Input.CruSession.SessionID())
|
||||||
|
}
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +269,10 @@ func (c *ApiController) Login() {
|
|||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !application.EnablePassword {
|
||||||
|
c.ResponseError(c.T("auth:The login method: login with password is not enabled for the application"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if object.CheckToEnableCaptcha(application) {
|
if object.CheckToEnableCaptcha(application) {
|
||||||
isHuman, err := captcha.VerifyCaptchaByCaptchaType(form.CaptchaType, form.CaptchaToken, form.ClientSecret)
|
isHuman, err := captcha.VerifyCaptchaByCaptchaType(form.CaptchaType, form.CaptchaToken, form.ClientSecret)
|
||||||
|
68
controllers/session.go
Normal file
68
controllers/session.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/beego/beego/utils/pagination"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"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
|
||||||
|
// @Param owner query string true "The organization name"
|
||||||
|
// @Success 200 {array} string The Response object
|
||||||
|
// @router /get-sessions [get]
|
||||||
|
func (c *ApiController) GetSessions() {
|
||||||
|
limit := c.Input().Get("pageSize")
|
||||||
|
page := c.Input().Get("p")
|
||||||
|
field := c.Input().Get("field")
|
||||||
|
value := c.Input().Get("value")
|
||||||
|
sortField := c.Input().Get("sortField")
|
||||||
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
if limit == "" || page == "" {
|
||||||
|
c.Data["json"] = object.GetSessions(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSessionCount(owner, field, value)))
|
||||||
|
sessions := object.GetPaginationSessions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
c.ResponseOk(sessions, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
@ -125,6 +125,127 @@ func (c *ApiController) GetUser() {
|
|||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkPermissionForUpdateUser(id string, newUser object.User, c *ApiController) (bool, string) {
|
||||||
|
oldUser := object.GetUser(id)
|
||||||
|
org := object.GetOrganizationByUser(oldUser)
|
||||||
|
var itemsChanged []*object.AccountItem
|
||||||
|
|
||||||
|
if oldUser.Owner != newUser.Owner {
|
||||||
|
item := object.GetAccountItemByName("Organization", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Name != newUser.Name {
|
||||||
|
item := object.GetAccountItemByName("Name", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Id != newUser.Id {
|
||||||
|
item := object.GetAccountItemByName("ID", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.DisplayName != newUser.DisplayName {
|
||||||
|
item := object.GetAccountItemByName("Display name", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Avatar != newUser.Avatar {
|
||||||
|
item := object.GetAccountItemByName("Avatar", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Type != newUser.Type {
|
||||||
|
item := object.GetAccountItemByName("User type", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
// The password is *** when not modified
|
||||||
|
if oldUser.Password != newUser.Password && newUser.Password != "***" {
|
||||||
|
item := object.GetAccountItemByName("Password", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Email != newUser.Email {
|
||||||
|
item := object.GetAccountItemByName("Email", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Phone != newUser.Phone {
|
||||||
|
item := object.GetAccountItemByName("Phone", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Region != newUser.Region {
|
||||||
|
item := object.GetAccountItemByName("Country/Region", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Location != newUser.Location {
|
||||||
|
item := object.GetAccountItemByName("Location", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Affiliation != newUser.Affiliation {
|
||||||
|
item := object.GetAccountItemByName("Affiliation", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Title != newUser.Title {
|
||||||
|
item := object.GetAccountItemByName("Title", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Homepage != newUser.Homepage {
|
||||||
|
item := object.GetAccountItemByName("Homepage", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Bio != newUser.Bio {
|
||||||
|
item := object.GetAccountItemByName("Bio", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Tag != newUser.Tag {
|
||||||
|
item := object.GetAccountItemByName("Tag", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.SignupApplication != newUser.SignupApplication {
|
||||||
|
item := object.GetAccountItemByName("Signup application", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserRolesJson, _ := json.Marshal(oldUser.Roles)
|
||||||
|
newUserRolesJson, _ := json.Marshal(newUser.Roles)
|
||||||
|
if string(oldUserRolesJson) != string(newUserRolesJson) {
|
||||||
|
item := object.GetAccountItemByName("Roles", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserPermissionJson, _ := json.Marshal(oldUser.Permissions)
|
||||||
|
newUserPermissionJson, _ := json.Marshal(newUser.Permissions)
|
||||||
|
if string(oldUserPermissionJson) != string(newUserPermissionJson) {
|
||||||
|
item := object.GetAccountItemByName("Permissions", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserPropertiesJson, _ := json.Marshal(oldUser.Properties)
|
||||||
|
newUserPropertiesJson, _ := json.Marshal(newUser.Properties)
|
||||||
|
if string(oldUserPropertiesJson) != string(newUserPropertiesJson) {
|
||||||
|
item := object.GetAccountItemByName("Properties", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldUser.IsAdmin != newUser.IsAdmin {
|
||||||
|
item := object.GetAccountItemByName("Is admin", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
|
||||||
|
item := object.GetAccountItemByName("Is global admin", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsForbidden != newUser.IsForbidden {
|
||||||
|
item := object.GetAccountItemByName("Is forbidden", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsDeleted != newUser.IsDeleted {
|
||||||
|
item := object.GetAccountItemByName("Is deleted", org)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range itemsChanged {
|
||||||
|
if pass, err := object.CheckAccountItemModifyRule(itemsChanged[i], c.getCurrentUser(), c.GetAcceptLanguage()); !pass {
|
||||||
|
return pass, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateUser
|
// UpdateUser
|
||||||
// @Title UpdateUser
|
// @Title UpdateUser
|
||||||
// @Tag User API
|
// @Tag User API
|
||||||
@ -159,6 +280,12 @@ func (c *ApiController) UpdateUser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isGlobalAdmin := c.IsGlobalAdmin()
|
isGlobalAdmin := c.IsGlobalAdmin()
|
||||||
|
|
||||||
|
if pass, err := checkPermissionForUpdateUser(id, user, c); !pass {
|
||||||
|
c.ResponseError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
||||||
if affected {
|
if affected {
|
||||||
object.UpdateUserToOriginalDatabase(&user)
|
object.UpdateUserToOriginalDatabase(&user)
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
"The provider type: %s is not supported": "The provider type: %s is not supported",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
@ -25,13 +25,14 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s 与用户名: %s (%s) 已经与其他账户绑定: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s 与用户名: %s (%s) 已经与其他账户绑定: %s (%s)",
|
||||||
"The application: %s does not exist": "应用 %s 不存在",
|
"The application: %s does not exist": "应用 %s 不存在",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider type: %s is not supported": "不支持该类型的提供商: %s",
|
"The provider type: %s is not supported": "不支持该类型的提供商: %s",
|
||||||
"The provider: %s is not enabled for the application": "提供商: %s 未被启用",
|
"The provider: %s is not enabled for the application": "提供商: %s 未被启用",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登陆,请联系管理员",
|
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登陆,请联系管理员",
|
||||||
"The user: %s/%s doesn't exist": "用户不存在: %s/%s",
|
"The user: %s/%s doesn't exist": "用户不存在: %s/%s",
|
||||||
"Turing test failed.": "真人验证失败",
|
"Turing test failed.": "真人验证失败",
|
||||||
"Unauthorized operation": "未授权的操作",
|
"Unauthorized operation": "未授权的操作",
|
||||||
"Unknown authentication type (not password or provider), form = %s": "未授权的操作"
|
"Unknown authentication type (not password or provider), form = %s": "未知的认证类型(非密码或第三方提供商):%s"
|
||||||
},
|
},
|
||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "服务 %s 与 %s 不匹配"
|
"Service %s and %s do not match": "服务 %s 与 %s 不匹配"
|
||||||
@ -89,7 +90,7 @@
|
|||||||
"You can't unlink yourself, you are not a member of any application": "您无法取消链接,您不是任何应用程序的成员"
|
"You can't unlink yourself, you are not a member of any application": "您无法取消链接,您不是任何应用程序的成员"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Only admin can modify the %s.": "您无法取消链接,您不是任何应用程序的成员",
|
"Only admin can modify the %s.": "仅允许管理员可以修改 %s",
|
||||||
"The %s is immutable.": "%s是不可变的",
|
"The %s is immutable.": "%s是不可变的",
|
||||||
"Unknown modify rule %s.": "未知的修改规则"
|
"Unknown modify rule %s.": "未知的修改规则"
|
||||||
},
|
},
|
||||||
|
@ -222,6 +222,11 @@ func (a *Adapter) createTable() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Session))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
||||||
|
@ -76,7 +76,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
|||||||
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
|
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
|
||||||
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
|
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
|
||||||
ResponseTypesSupported: []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"},
|
ResponseTypesSupported: []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"},
|
||||||
ResponseModesSupported: []string{"login", "code", "link"},
|
ResponseModesSupported: []string{"query", "fragment", "login", "code", "link"},
|
||||||
GrantTypesSupported: []string{"password", "authorization_code"},
|
GrantTypesSupported: []string{"password", "authorization_code"},
|
||||||
SubjectTypesSupported: []string{"public"},
|
SubjectTypesSupported: []string{"public"},
|
||||||
IdTokenSigningAlgValuesSupported: []string{"RS256"},
|
IdTokenSigningAlgValuesSupported: []string{"RS256"},
|
||||||
|
@ -269,3 +269,12 @@ func ContainsAsterisk(userId string, users []string) bool {
|
|||||||
|
|
||||||
return containsAsterisk
|
return containsAsterisk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMaskedPermissions(permissions []*Permission) []*Permission {
|
||||||
|
for _, permission := range permissions {
|
||||||
|
permission.Users = nil
|
||||||
|
permission.Submitter = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions
|
||||||
|
}
|
||||||
|
@ -192,3 +192,11 @@ func roleChangeTrigger(oldName string, newName string) error {
|
|||||||
|
|
||||||
return session.Commit()
|
return session.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMaskedRoles(roles []*Role) []*Role {
|
||||||
|
for _, role := range roles {
|
||||||
|
role.Users = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
@ -223,11 +223,14 @@ func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, e
|
|||||||
|
|
||||||
// GetSamlResponse generates a SAML2.0 response
|
// GetSamlResponse generates a SAML2.0 response
|
||||||
// parameter samlRequest is saml request in base64 format
|
// parameter samlRequest is saml request in base64 format
|
||||||
func GetSamlResponse(application *Application, user *User, samlRequest string, host string) (string, string, error) {
|
func GetSamlResponse(application *Application, user *User, samlRequest string, host string) (string, string, string, error) {
|
||||||
|
// request type
|
||||||
|
method := "GET"
|
||||||
|
|
||||||
// base64 decode
|
// base64 decode
|
||||||
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
||||||
}
|
}
|
||||||
// decompress
|
// decompress
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
@ -236,12 +239,12 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
var authnRequest saml.AuthnRequest
|
var authnRequest saml.AuthnRequest
|
||||||
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify samlRequest
|
// verify samlRequest
|
||||||
if isValid := application.IsRedirectUriValid(authnRequest.Issuer.Url); !isValid {
|
if isValid := application.IsRedirectUriValid(authnRequest.Issuer.Url); !isValid {
|
||||||
return "", "", fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer.Url)
|
return "", "", method, fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer.Url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get certificate string
|
// get certificate string
|
||||||
@ -253,6 +256,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
|
|
||||||
// redirect Url (Assertion Consumer Url)
|
// redirect Url (Assertion Consumer Url)
|
||||||
if application.SamlReplyUrl != "" {
|
if application.SamlReplyUrl != "" {
|
||||||
|
method = "POST"
|
||||||
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
|
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +279,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
doc.SetRoot(samlResponse)
|
doc.SetRoot(samlResponse)
|
||||||
xmlBytes, err := doc.WriteToBytes()
|
xmlBytes, err := doc.WriteToBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// compress
|
// compress
|
||||||
@ -283,7 +287,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
flated := bytes.NewBuffer(nil)
|
flated := bytes.NewBuffer(nil)
|
||||||
writer, err := flate.NewWriter(flated, flate.DefaultCompression)
|
writer, err := flate.NewWriter(flated, flate.DefaultCompression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
||||||
}
|
}
|
||||||
writer.Write(xmlBytes)
|
writer.Write(xmlBytes)
|
||||||
writer.Close()
|
writer.Close()
|
||||||
@ -291,7 +295,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
}
|
}
|
||||||
// base64 encode
|
// base64 encode
|
||||||
res := base64.StdEncoding.EncodeToString(xmlBytes)
|
res := base64.StdEncoding.EncodeToString(xmlBytes)
|
||||||
return res, authnRequest.AssertionConsumerServiceURL, nil
|
return res, authnRequest.AssertionConsumerServiceURL, method, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSamlResponse11 return a saml1.1 response(not 2.0)
|
// NewSamlResponse11 return a saml1.1 response(not 2.0)
|
||||||
|
132
object/session.go
Normal file
132
object/session.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/beego/beego"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"xorm.io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = time.Now().Format(time.RFC3339)
|
||||||
|
_, 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.GetOwnerAndNameFromIdNoCheck(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
|
||||||
|
if owner != "" {
|
||||||
|
err = adapter.Engine.Desc("created_time").Where("owner = ?", owner).Find(&sessions)
|
||||||
|
} else {
|
||||||
|
err = adapter.Engine.Desc("created_time").Find(&sessions)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessions
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationSessions(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Session {
|
||||||
|
sessions := []*Session{}
|
||||||
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Find(&sessions)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessions
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSessionCount(owner, field, value string) int {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&Session{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
@ -529,6 +529,9 @@ func AddUsersInBatch(users []*User) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUser(user *User) bool {
|
func DeleteUser(user *User) bool {
|
||||||
|
// Forced offline the user first
|
||||||
|
DeleteSession(user.GetId())
|
||||||
|
|
||||||
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
|
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -164,6 +164,9 @@ func initAPI() {
|
|||||||
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
|
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
|
||||||
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
|
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
|
||||||
|
|
||||||
|
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
|
||||||
|
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
|
||||||
|
|
||||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||||
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
||||||
|
25
util/slice.go
Normal file
25
util/slice.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
func DeleteVal(values []string, val string) []string {
|
||||||
|
newValues := []string{}
|
||||||
|
for _, v := range values {
|
||||||
|
if v != val {
|
||||||
|
newValues = append(newValues, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newValues
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
"@testing-library/user-event": "^7.1.2",
|
"@testing-library/user-event": "^7.1.2",
|
||||||
"antd": "5.0.5",
|
"antd": "5.1.2",
|
||||||
"codemirror": "^5.61.1",
|
"codemirror": "^5.61.1",
|
||||||
"copy-to-clipboard": "^3.3.1",
|
"copy-to-clipboard": "^3.3.1",
|
||||||
"core-js": "^3.25.0",
|
"core-js": "^3.25.0",
|
||||||
|
@ -170,7 +170,7 @@ class AccountTable extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let options;
|
let options;
|
||||||
if (record.viewRule === "Admin") {
|
if (record.viewRule === "Admin" || record.name === "Is admin" || record.name === "Is global admin") {
|
||||||
options = [
|
options = [
|
||||||
{id: "Admin", name: "Admin"},
|
{id: "Admin", name: "Admin"},
|
||||||
{id: "Immutable", name: "Immutable"},
|
{id: "Immutable", name: "Immutable"},
|
||||||
|
@ -260,6 +260,13 @@ class AdapterListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
181
web/src/App.js
181
web/src/App.js
@ -17,7 +17,7 @@ import "./App.less";
|
|||||||
import {Helmet} from "react-helmet";
|
import {Helmet} from "react-helmet";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import {BarsOutlined, DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
|
import {BarsOutlined, DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
|
||||||
import {Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd";
|
import {Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result, theme} from "antd";
|
||||||
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
||||||
import OrganizationListPage from "./OrganizationListPage";
|
import OrganizationListPage from "./OrganizationListPage";
|
||||||
import OrganizationEditPage from "./OrganizationEditPage";
|
import OrganizationEditPage from "./OrganizationEditPage";
|
||||||
@ -69,6 +69,8 @@ import SystemInfo from "./SystemInfo";
|
|||||||
import AdapterListPage from "./AdapterListPage";
|
import AdapterListPage from "./AdapterListPage";
|
||||||
import AdapterEditPage from "./AdapterEditPage";
|
import AdapterEditPage from "./AdapterEditPage";
|
||||||
import {withTranslation} from "react-i18next";
|
import {withTranslation} from "react-i18next";
|
||||||
|
import SelectThemeBox from "./SelectThemeBox";
|
||||||
|
import SessionListPage from "./SessionListPage";
|
||||||
|
|
||||||
const {Header, Footer, Content} = Layout;
|
const {Header, Footer, Content} = Layout;
|
||||||
|
|
||||||
@ -81,6 +83,8 @@ class App extends Component {
|
|||||||
account: undefined,
|
account: undefined,
|
||||||
uri: null,
|
uri: null,
|
||||||
menuVisible: false,
|
menuVisible: false,
|
||||||
|
themeAlgorithm: null,
|
||||||
|
logo: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
Setting.initServerUrl();
|
Setting.initServerUrl();
|
||||||
@ -95,6 +99,16 @@ class App extends Component {
|
|||||||
this.getAccount();
|
this.getAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
localStorage.getItem("theme") ?
|
||||||
|
this.setState({"themeAlgorithm": this.getTheme()}) : this.setState({"themeAlgorithm": theme.defaultAlgorithm});
|
||||||
|
this.setState({"logo": Setting.getLogo(localStorage.getItem("theme"))});
|
||||||
|
addEventListener("themeChange", (e) => {
|
||||||
|
this.setState({"themeAlgorithm": this.getTheme()});
|
||||||
|
this.setState({"logo": Setting.getLogo(localStorage.getItem("theme"))});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
// eslint-disable-next-line no-restricted-globals
|
// eslint-disable-next-line no-restricted-globals
|
||||||
const uri = location.pathname;
|
const uri = location.pathname;
|
||||||
@ -184,6 +198,10 @@ class App extends Component {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTheme() {
|
||||||
|
return Setting.Themes.find(t => t.key === localStorage.getItem("theme"))["style"];
|
||||||
|
}
|
||||||
|
|
||||||
setLanguage(account) {
|
setLanguage(account) {
|
||||||
const language = account?.language;
|
const language = account?.language;
|
||||||
if (language !== "" && language !== i18next.language) {
|
if (language !== "" && language !== i18next.language) {
|
||||||
@ -404,6 +422,10 @@ class App extends Component {
|
|||||||
"/tokens"
|
"/tokens"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
res.push(Setting.getItem(<Link to="/sessions">{i18next.t("general:Sessions")}</Link>,
|
||||||
|
"/sessions"
|
||||||
|
));
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/webhooks">{i18next.t("general:Webhooks")}</Link>,
|
res.push(Setting.getItem(<Link to="/webhooks">{i18next.t("general:Webhooks")}</Link>,
|
||||||
"/webhooks"
|
"/webhooks"
|
||||||
));
|
));
|
||||||
@ -465,54 +487,63 @@ class App extends Component {
|
|||||||
|
|
||||||
renderRouter() {
|
renderRouter() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<ConfigProvider theme={{
|
||||||
<Switch>
|
token: {
|
||||||
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
colorPrimary: "rgb(89,54,213)",
|
||||||
<Route exact path="/result/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
colorInfo: "rgb(89,54,213)",
|
||||||
<Route exact path="/" render={(props) => this.renderLoginIfNotLoggedIn(<HomePage account={this.state.account} {...props} />)} />
|
},
|
||||||
<Route exact path="/account" render={(props) => this.renderLoginIfNotLoggedIn(<AccountPage account={this.state.account} {...props} />)} />
|
algorithm: this.state.themeAlgorithm,
|
||||||
<Route exact path="/organizations" render={(props) => this.renderLoginIfNotLoggedIn(<OrganizationListPage account={this.state.account} {...props} />)} />
|
}}>
|
||||||
<Route exact path="/organizations/:organizationName" render={(props) => this.renderLoginIfNotLoggedIn(<OrganizationEditPage account={this.state.account} {...props} />)} />
|
<div>
|
||||||
<Route exact path="/organizations/:organizationName/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
<Switch>
|
||||||
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
||||||
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />} />
|
<Route exact path="/result/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
||||||
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/" render={(props) => this.renderLoginIfNotLoggedIn(<HomePage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/account" render={(props) => this.renderLoginIfNotLoggedIn(<AccountPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/organizations" render={(props) => this.renderLoginIfNotLoggedIn(<OrganizationListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/organizations/:organizationName" render={(props) => this.renderLoginIfNotLoggedIn(<OrganizationEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/models" render={(props) => this.renderLoginIfNotLoggedIn(<ModelListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/organizations/:organizationName/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/models/:organizationName/:modelName" render={(props) => this.renderLoginIfNotLoggedIn(<ModelEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/adapters" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />} />
|
||||||
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/models" render={(props) => this.renderLoginIfNotLoggedIn(<ModelListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/models/:organizationName/:modelName" render={(props) => this.renderLoginIfNotLoggedIn(<ModelEditPage account={this.state.account} {...props} />)} />
|
||||||
{/* <Route exact path="/resources/:resourceName" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceEditPage account={this.state.account} {...props} />)}/>*/}
|
<Route exact path="/adapters" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/ldap/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/ldap/sync/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/tokens/:tokenName" render={(props) => this.renderLoginIfNotLoggedIn(<TokenEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
{/* <Route exact path="/resources/:resourceName" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceEditPage account={this.state.account} {...props} />)}/>*/}
|
||||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/ldap/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/ldap/sync/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/certs/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/sessions" render={(props) => this.renderLoginIfNotLoggedIn(<SessionListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/tokens/:tokenName" render={(props) => this.renderLoginIfNotLoggedIn(<TokenEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
<Route exact path="/certs/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)} />
|
||||||
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
<Route exact path="/products/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
||||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
<Route exact path="/products/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
||||||
</Switch>
|
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
||||||
</div>
|
<Route exact path="/payments/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/payments/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
||||||
|
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
||||||
|
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,30 +563,27 @@ class App extends Component {
|
|||||||
if (!Setting.isMobile()) {
|
if (!Setting.isMobile()) {
|
||||||
return (
|
return (
|
||||||
<Layout id="parent-area">
|
<Layout id="parent-area">
|
||||||
<Header style={{marginBottom: "3px", paddingInline: 0}}>
|
<Header style={{marginBottom: "3px", paddingInline: 0, backgroundColor: this.state.themeAlgorithm === theme.darkAlgorithm ? "black" : "white"}}>
|
||||||
{
|
{
|
||||||
Setting.isMobile() ? null : (
|
Setting.isMobile() ? null : (
|
||||||
<Link to={"/"}>
|
<Link to={"/"}>
|
||||||
<div className="logo" />
|
<div className="logo" style={{background: `url(${this.state.logo})`}} />
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div>
|
<Menu
|
||||||
<Menu
|
items={this.renderMenu()}
|
||||||
// theme="dark"
|
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
||||||
items={this.renderMenu()}
|
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
||||||
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
style={{position: "absolute", left: "145px", backgroundColor: this.state.themeAlgorithm === theme.darkAlgorithm ? "black" : "white"}}
|
||||||
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
/>
|
||||||
style={{lineHeight: "64px", position: "absolute", left: "145px", right: "200px"}}
|
{
|
||||||
>
|
this.renderAccount()
|
||||||
</Menu>
|
}
|
||||||
{
|
{this.state.account && <SelectThemeBox themes={this.state.account.organization.themes} />}
|
||||||
this.renderAccount()
|
{this.state.account && <SelectLanguageBox languages={this.state.account.organization.languages} />}
|
||||||
}
|
|
||||||
{this.state.account && <SelectLanguageBox languages={this.state.account.organization.languages} />}
|
|
||||||
</div>
|
|
||||||
</Header>
|
</Header>
|
||||||
<Content style={{backgroundColor: "#f5f5f5", alignItems: "stretch", display: "flex", flexDirection: "column"}}>
|
<Content style={{alignItems: "stretch", display: "flex", flexDirection: "column"}}>
|
||||||
<Card className="content-warp-card">
|
<Card className="content-warp-card">
|
||||||
{
|
{
|
||||||
this.renderRouter()
|
this.renderRouter()
|
||||||
@ -570,11 +598,11 @@ class App extends Component {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Header style={{padding: "0", marginBottom: "3px"}}>
|
<Header style={{padding: "0", marginBottom: "3px", backgroundColor: this.state.themeAlgorithm === theme.darkAlgorithm ? "black" : "white"}}>
|
||||||
{
|
{
|
||||||
Setting.isMobile() ? null : (
|
Setting.isMobile() ? null : (
|
||||||
<Link to={"/"}>
|
<Link to={"/"}>
|
||||||
<div className="logo" />
|
<div className="logo" style={{background: `url(${this.state.logo})`}} />
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -592,12 +620,11 @@ class App extends Component {
|
|||||||
<Button icon={<BarsOutlined />} onClick={this.showMenu} type="text">
|
<Button icon={<BarsOutlined />} onClick={this.showMenu} type="text">
|
||||||
{i18next.t("general:Menu")}
|
{i18next.t("general:Menu")}
|
||||||
</Button>
|
</Button>
|
||||||
<div style = {{float: "right"}}>
|
{
|
||||||
{
|
this.renderAccount()
|
||||||
this.renderAccount()
|
}
|
||||||
}
|
{this.state.account && <SelectThemeBox themes={this.state.account.organization.themes} />}
|
||||||
{this.state.account && <SelectLanguageBox languages={this.state.account.organization.languages} />}
|
{this.state.account && <SelectLanguageBox languages={this.state.account.organization.languages} />}
|
||||||
</div>
|
|
||||||
</Header>
|
</Header>
|
||||||
<Content style={{display: "flex", flexDirection: "column"}} >{
|
<Content style={{display: "flex", flexDirection: "column"}} >{
|
||||||
this.renderRouter()}
|
this.renderRouter()}
|
||||||
@ -617,12 +644,10 @@ class App extends Component {
|
|||||||
{!this.state.account ? null : <div style={{display: "none"}} id="CasdoorApplicationName" value={this.state.account.signupApplication} />}
|
{!this.state.account ? null : <div style={{display: "none"}} id="CasdoorApplicationName" value={this.state.account.signupApplication} />}
|
||||||
<Footer id="footer" style={
|
<Footer id="footer" style={
|
||||||
{
|
{
|
||||||
borderTop: "1px solid #e8e8e8",
|
|
||||||
backgroundColor: "white",
|
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
Powered by <a target="_blank" href="https://casdoor.org" rel="noreferrer"><img style={{paddingBottom: "3px"}} height={"20px"} alt={"Casdoor"} src={`${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`} /></a>
|
Powered by <a target="_blank" href="https://casdoor.org" rel="noreferrer"><img style={{paddingBottom: "3px"}} height={"20px"} alt={"Casdoor"} src={this.state.logo} /></a>
|
||||||
</Footer>
|
</Footer>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
@ -690,6 +715,7 @@ class App extends Component {
|
|||||||
colorPrimary: "rgb(89,54,213)",
|
colorPrimary: "rgb(89,54,213)",
|
||||||
colorInfo: "rgb(89,54,213)",
|
colorInfo: "rgb(89,54,213)",
|
||||||
},
|
},
|
||||||
|
algorithm: this.state.themeAlgorithm,
|
||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
this.renderPage()
|
this.renderPage()
|
||||||
@ -711,6 +737,7 @@ class App extends Component {
|
|||||||
colorPrimary: "rgb(89,54,213)",
|
colorPrimary: "rgb(89,54,213)",
|
||||||
colorInfo: "rgb(89,54,213)",
|
colorInfo: "rgb(89,54,213)",
|
||||||
},
|
},
|
||||||
|
algorithm: this.state.themeAlgorithm,
|
||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
this.renderPage()
|
this.renderPage()
|
||||||
|
@ -13,14 +13,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.App-header {
|
.App-header {
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: calc(10px + 2vmin);
|
font-size: calc(10px + 2vmin);
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-link {
|
.App-link {
|
||||||
@ -41,7 +39,6 @@ img {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-logo {
|
.panel-logo {
|
||||||
@ -55,7 +52,7 @@ img {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
width: 45px;
|
width: 45px;
|
||||||
height: 65px;
|
height: 100%;
|
||||||
float: right;
|
float: right;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@ -64,9 +61,32 @@ img {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-form .language-box {
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-box {
|
||||||
|
background: url("@{StaticBaseUrl}/img/muti_language.svg");
|
||||||
|
background-size: 25px, 25px;
|
||||||
|
background-position: center !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 45px;
|
||||||
|
height: 100%;
|
||||||
|
float: right;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f5f5f5 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.rightDropDown {
|
.rightDropDown {
|
||||||
|
border-radius: 7px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,3 +148,9 @@ img {
|
|||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-menu-horizontal {
|
||||||
|
border-bottom: none !important;
|
||||||
|
margin-right: 30px;
|
||||||
|
right: 230px;
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Card, Col, Input, Popover, Radio, Row, Select, Switch, Upload} from "antd";
|
import {Button, Card, Col, Input, Popover, Radio, Result, Row, Select, Switch, Upload} from "antd";
|
||||||
import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
|
import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
|
||||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||||
import * as CertBackend from "./backend/CertBackend";
|
import * as CertBackend from "./backend/CertBackend";
|
||||||
@ -103,6 +103,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
uploading: false,
|
uploading: false,
|
||||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||||
samlMetadata: null,
|
samlMetadata: null,
|
||||||
|
isAuthorized: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +130,15 @@ class ApplicationEditPage extends React.Component {
|
|||||||
getOrganizations() {
|
getOrganizations() {
|
||||||
OrganizationBackend.getOrganizations("admin")
|
OrganizationBackend.getOrganizations("admin")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.setState({
|
if (res?.status === "error") {
|
||||||
organizations: (res.msg === undefined) ? res : [],
|
this.setState({
|
||||||
});
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
organizations: (res.msg === undefined) ? res : [],
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,6 +845,17 @@ class ApplicationEditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Button, Col, List, Popconfirm, Row, Table, Tooltip} from "antd";
|
import {Button, Col, List, Popconfirm, Result, Row, Table, Tooltip} from "antd";
|
||||||
import {EditOutlined} from "@ant-design/icons";
|
import {EditOutlined} from "@ant-design/icons";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
@ -36,6 +36,7 @@ class ApplicationListPage extends BaseListPage {
|
|||||||
loading: false,
|
loading: false,
|
||||||
searchText: "",
|
searchText: "",
|
||||||
searchedColumn: "",
|
searchedColumn: "",
|
||||||
|
isAuthorized: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +259,17 @@ class ApplicationListPage extends BaseListPage {
|
|||||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table scroll={{x: "max-content"}} columns={columns} dataSource={applications} rowKey="name" size="middle" bordered pagination={paginationProps}
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={applications} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||||
@ -292,6 +304,13 @@ class ApplicationListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -13,9 +13,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Input, Space} from "antd";
|
import {Button, Input, Result, Space} from "antd";
|
||||||
import {SearchOutlined} from "@ant-design/icons";
|
import {SearchOutlined} from "@ant-design/icons";
|
||||||
import Highlighter from "react-highlight-words";
|
import Highlighter from "react-highlight-words";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
class BaseListPage extends React.Component {
|
class BaseListPage extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -127,6 +128,17 @@ class BaseListPage extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
|
@ -227,6 +227,13 @@ class CertListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -200,6 +200,13 @@ class ModelListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -251,7 +251,7 @@ class OrganizationListPage extends BaseListPage {
|
|||||||
<Result
|
<Result
|
||||||
status="403"
|
status="403"
|
||||||
title="403 Unauthorized"
|
title="403 Unauthorized"
|
||||||
subTitle={i18next.t("general:Sorry, you do not have permission to access this page.")}
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -278,6 +278,13 @@ class PaymentListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -358,6 +358,13 @@ class PermissionListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -295,6 +295,13 @@ class ProductListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Button, Popconfirm, Table} from "antd";
|
import {Button, Popconfirm, Result, Table} from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||||
@ -36,6 +36,7 @@ class ProviderListPage extends BaseListPage {
|
|||||||
loading: false,
|
loading: false,
|
||||||
searchText: "",
|
searchText: "",
|
||||||
searchedColumn: "",
|
searchedColumn: "",
|
||||||
|
isAuthorized: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
newProvider() {
|
newProvider() {
|
||||||
@ -227,6 +228,17 @@ class ProviderListPage extends BaseListPage {
|
|||||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table scroll={{x: "max-content"}} columns={columns} dataSource={providers} rowKey="name" size="middle" bordered pagination={paginationProps}
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={providers} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||||
@ -268,6 +280,13 @@ class ProviderListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -222,6 +222,13 @@ class RecordListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.data.includes("Please login first")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Popconfirm, Table, Upload} from "antd";
|
import {Button, Popconfirm, Result, Table, Upload} from "antd";
|
||||||
import {UploadOutlined} from "@ant-design/icons";
|
import {UploadOutlined} from "@ant-design/icons";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
@ -37,6 +37,7 @@ class ResourceListPage extends BaseListPage {
|
|||||||
searchedColumn: "",
|
searchedColumn: "",
|
||||||
fileList: [],
|
fileList: [],
|
||||||
uploading: false,
|
uploading: false,
|
||||||
|
isAuthorized: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,6 +273,17 @@ class ResourceListPage extends BaseListPage {
|
|||||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table scroll={{x: "max-content"}} columns={columns} dataSource={resources} rowKey="name" size="middle" bordered pagination={paginationProps}
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={resources} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||||
@ -308,6 +320,13 @@ class ResourceListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.data.includes("Please login first")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -231,6 +231,13 @@ class RoleListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
81
web/src/SelectThemeBox.js
Normal file
81
web/src/SelectThemeBox.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import {Dropdown} from "antd";
|
||||||
|
import "./App.less";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
function themeIcon(themeKey) {
|
||||||
|
return <img width={24} alt={themeKey} src={getLogoURL(themeKey)} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLogoURL(themeKey) {
|
||||||
|
if (themeKey) {
|
||||||
|
return Setting.Themes.find(t => t.key === themeKey)["selectThemeLogo"];
|
||||||
|
} else {
|
||||||
|
return Setting.Themes.find(t => t.key === localStorage.getItem("theme"))["selectThemeLogo"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectThemeBox extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
themes: props.theme ?? ["Default", "Dark", "Compact"],
|
||||||
|
icon: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
items = this.getThemes();
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
i18next.on("languageChanged", () => {
|
||||||
|
this.items = this.getThemes();
|
||||||
|
});
|
||||||
|
localStorage.getItem("theme") ? this.setState({"icon": getLogoURL()}) : this.setState({"icon": getLogoURL("Default")});
|
||||||
|
addEventListener("themeChange", (e) => {
|
||||||
|
this.setState({"icon": getLogoURL()});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getThemes() {
|
||||||
|
return Setting.Themes.map((theme) => Setting.getItem(i18next.t(`general:${theme.label}`), theme.key, themeIcon(theme.key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrganizationThemes(themes) {
|
||||||
|
const select = [];
|
||||||
|
for (const theme of themes) {
|
||||||
|
this.items.map((item, index) => item.key === theme ? select.push(item) : null);
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const themeItems = this.getOrganizationThemes(this.state.themes);
|
||||||
|
const onClick = (e) => {
|
||||||
|
Setting.setTheme(e.key);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown menu={{items: themeItems, onClick}} >
|
||||||
|
<div className="theme-box" style={{display: themeItems.length === 0 ? "none" : null, background: `url(${this.state.icon})`, ...this.props.style}} />
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectThemeBox;
|
162
web/src/SessionListPage.js
Normal file
162
web/src/SessionListPage.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// 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 BaseListPage from "./BaseListPage";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {Button, Popconfirm, Table, Tag} from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import * as SessionBackend from "./backend/SessionBackend";
|
||||||
|
|
||||||
|
class SessionListPage extends BaseListPage {
|
||||||
|
|
||||||
|
deleteSession(i) {
|
||||||
|
SessionBackend.deleteSession(this.state.data[i])
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||||
|
this.setState({
|
||||||
|
data: Setting.deleteRow(this.state.data, i),
|
||||||
|
pagination: {total: this.state.pagination.total - 1},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(sessions) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Name"),
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
width: "150px",
|
||||||
|
fixed: "left",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("name"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Organization"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "organization",
|
||||||
|
width: "110px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("organization"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/organizations/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Created time"),
|
||||||
|
dataIndex: "createdTime",
|
||||||
|
key: "createdTime",
|
||||||
|
width: "180px",
|
||||||
|
sorter: true,
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return Setting.getFormattedDate(text);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Session ID"),
|
||||||
|
dataIndex: "sessionId",
|
||||||
|
key: "sessionId",
|
||||||
|
width: "180px",
|
||||||
|
sorter: true,
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return text.map((item, index) =>
|
||||||
|
<Tag key={index}>{item}</Tag>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Action"),
|
||||||
|
dataIndex: "",
|
||||||
|
key: "op",
|
||||||
|
width: "70px",
|
||||||
|
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Popconfirm
|
||||||
|
title={`Sure to delete session: ${record.name} ?`}
|
||||||
|
onConfirm={() => this.deleteSession(index)}
|
||||||
|
>
|
||||||
|
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const paginationProps = {
|
||||||
|
total: this.state.pagination.total,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={sessions} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||||
|
loading={this.state.loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
let field = params.searchedColumn, value = params.searchText;
|
||||||
|
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||||
|
if (params.contentType !== undefined && params.contentType !== null) {
|
||||||
|
field = "contentType";
|
||||||
|
value = params.contentType;
|
||||||
|
}
|
||||||
|
this.setState({loading: true});
|
||||||
|
SessionBackend.getSessions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
data: res.data,
|
||||||
|
pagination: {
|
||||||
|
...params.pagination,
|
||||||
|
total: res.data2,
|
||||||
|
},
|
||||||
|
searchText: params.searchText,
|
||||||
|
searchedColumn: params.searchedColumn,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SessionListPage;
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Tag, Tooltip, message} from "antd";
|
import {Tag, Tooltip, message, theme} from "antd";
|
||||||
import {QuestionCircleTwoTone} from "@ant-design/icons";
|
import {QuestionCircleTwoTone} from "@ant-design/icons";
|
||||||
import {isMobile as isMobileDevice} from "react-device-detect";
|
import {isMobile as isMobileDevice} from "react-device-detect";
|
||||||
import "./i18n";
|
import "./i18n";
|
||||||
@ -43,6 +43,13 @@ export const Countries = [{label: "English", key: "en", country: "US", alt: "Eng
|
|||||||
{label: "Русский", key: "ru", country: "RU", alt: "Русский"},
|
{label: "Русский", key: "ru", country: "RU", alt: "Русский"},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const {defaultAlgorithm, darkAlgorithm, compactAlgorithm} = theme;
|
||||||
|
|
||||||
|
export const Themes = [{label: i18next.t("general:Dark"), key: "Dark", style: darkAlgorithm, selectThemeLogo: `${StaticBaseUrl}/img/dark.svg`},
|
||||||
|
{label: i18next.t("general:Compact"), key: "Compact", style: compactAlgorithm, selectThemeLogo: `${StaticBaseUrl}/img/compact.svg`},
|
||||||
|
{label: i18next.t("general:Default"), key: "Default", style: defaultAlgorithm, selectThemeLogo: `${StaticBaseUrl}/img/light.svg`},
|
||||||
|
];
|
||||||
|
|
||||||
export const OtherProviderInfo = {
|
export const OtherProviderInfo = {
|
||||||
SMS: {
|
SMS: {
|
||||||
"Aliyun SMS": {
|
"Aliyun SMS": {
|
||||||
@ -562,6 +569,14 @@ export function getAvatarColor(s) {
|
|||||||
return colorList[hash % 4];
|
return colorList[hash % 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLogo(theme) {
|
||||||
|
if (theme === "Dark") {
|
||||||
|
return `${StaticBaseUrl}/img/casdoor-logo_1185x256_dark.png`;
|
||||||
|
} else {
|
||||||
|
return `${StaticBaseUrl}/img/casdoor-logo_1185x256.png`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getLanguageText(text) {
|
export function getLanguageText(text) {
|
||||||
if (!text.includes("|")) {
|
if (!text.includes("|")) {
|
||||||
return text;
|
return text;
|
||||||
@ -587,6 +602,11 @@ export function setLanguage(language) {
|
|||||||
i18next.changeLanguage(language);
|
i18next.changeLanguage(language);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setTheme(themeKey) {
|
||||||
|
localStorage.setItem("theme", themeKey);
|
||||||
|
dispatchEvent(new Event("themeChange"));
|
||||||
|
}
|
||||||
|
|
||||||
export function getAcceptLanguage() {
|
export function getAcceptLanguage() {
|
||||||
if (i18next.language === null || i18next.language === "") {
|
if (i18next.language === null || i18next.language === "") {
|
||||||
return "en;q=0.9,en;q=0.8";
|
return "en;q=0.9,en;q=0.8";
|
||||||
|
@ -288,6 +288,13 @@ class SyncerListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -253,6 +253,13 @@ class TokenListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -28,11 +28,7 @@ import SamlWidget from "./common/SamlWidget";
|
|||||||
import SelectRegionBox from "./SelectRegionBox";
|
import SelectRegionBox from "./SelectRegionBox";
|
||||||
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
|
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
|
||||||
import ManagedAccountTable from "./ManagedAccountTable";
|
import ManagedAccountTable from "./ManagedAccountTable";
|
||||||
|
import PropertyTable from "./propertyTable";
|
||||||
import {Controlled as CodeMirror} from "react-codemirror2";
|
|
||||||
import "codemirror/lib/codemirror.css";
|
|
||||||
require("codemirror/theme/material-darker.css");
|
|
||||||
require("codemirror/mode/javascript/javascript");
|
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
@ -490,13 +486,10 @@ class UserEditPage extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{i18next.t("user:Properties")}:
|
{Setting.getLabel(i18next.t("user:Properties"), i18next.t("user:Properties - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<CodeMirror
|
<PropertyTable properties={this.state.user.properties} onUpdateTable={(value) => {this.updateUserField("properties", value);}} />
|
||||||
value={JSON.stringify(this.state.user.properties, null, 4)}
|
|
||||||
options={{mode: "javascript", theme: "material-darker"}}
|
|
||||||
/>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
@ -507,7 +500,7 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("user:Is admin"), i18next.t("user:Is admin - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Is admin"), i18next.t("user:Is admin - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
<Switch disabled={this.state.user.owner === "built-in"} checked={this.state.user.isAdmin} onChange={checked => {
|
<Switch disabled={disabled} checked={this.state.user.isAdmin} onChange={checked => {
|
||||||
this.updateUserField("isAdmin", checked);
|
this.updateUserField("isAdmin", checked);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
@ -520,7 +513,7 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("user:Is global admin"), i18next.t("user:Is global admin - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Is global admin"), i18next.t("user:Is global admin - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
<Switch disabled={this.state.user.owner === "built-in"} checked={this.state.user.isGlobalAdmin} onChange={checked => {
|
<Switch disabled={disabled} checked={this.state.user.isGlobalAdmin} onChange={checked => {
|
||||||
this.updateUserField("isGlobalAdmin", checked);
|
this.updateUserField("isGlobalAdmin", checked);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Button, Popconfirm, Switch, Table, Upload} from "antd";
|
import {Button, Popconfirm, Result, Switch, Table, Upload} from "antd";
|
||||||
import {UploadOutlined} from "@ant-design/icons";
|
import {UploadOutlined} from "@ant-design/icons";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||||
@ -38,6 +38,7 @@ class UserListPage extends BaseListPage {
|
|||||||
loading: false,
|
loading: false,
|
||||||
searchText: "",
|
searchText: "",
|
||||||
searchedColumn: "",
|
searchedColumn: "",
|
||||||
|
isAuthorized: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,6 +370,17 @@ class UserListPage extends BaseListPage {
|
|||||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this.state.isAuthorized) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="403 Unauthorized"
|
||||||
|
subTitle={i18next.t("general:Sorry, you do not have permission to access this page or logged in status invalid.")}
|
||||||
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table scroll={{x: "max-content"}} columns={columns} dataSource={users} rowKey={(record) => `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps}
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={users} rowKey={(record) => `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps}
|
||||||
@ -411,6 +423,13 @@ class UserListPage extends BaseListPage {
|
|||||||
if (users.length > 0) {
|
if (users.length > 0) {
|
||||||
this.getOrganization(users[0].owner);
|
this.getOrganization(users[0].owner);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -432,6 +451,13 @@ class UserListPage extends BaseListPage {
|
|||||||
if (users.length > 0) {
|
if (users.length > 0) {
|
||||||
this.getOrganization(users[0].owner);
|
this.getOrganization(users[0].owner);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,13 @@ class WebhookListPage extends BaseListPage {
|
|||||||
searchText: params.searchText,
|
searchText: params.searchText,
|
||||||
searchedColumn: params.searchedColumn,
|
searchedColumn: params.searchedColumn,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (res.msg.includes("Unauthorized")) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ import * as Util from "./Util";
|
|||||||
import {authConfig} from "./Auth";
|
import {authConfig} from "./Auth";
|
||||||
import * as Setting from "../Setting";
|
import * as Setting from "../Setting";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import RedirectForm from "../common/RedirectForm";
|
||||||
|
|
||||||
class AuthCallback extends React.Component {
|
class AuthCallback extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -27,6 +28,9 @@ class AuthCallback extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
msg: null,
|
msg: null,
|
||||||
|
samlResponse: "",
|
||||||
|
relayState: "",
|
||||||
|
redirectUrl: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,9 +168,17 @@ class AuthCallback extends React.Component {
|
|||||||
const from = innerParams.get("from");
|
const from = innerParams.get("from");
|
||||||
Setting.goToLinkSoft(this, from);
|
Setting.goToLinkSoft(this, from);
|
||||||
} else if (responseType === "saml") {
|
} else if (responseType === "saml") {
|
||||||
const SAMLResponse = res.data;
|
if (res.data2.method === "POST") {
|
||||||
const redirectUri = res.data2;
|
this.setState({
|
||||||
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);
|
samlResponse: res.data,
|
||||||
|
redirectUrl: res.data2.redirectUrl,
|
||||||
|
relayState: oAuthParams.relayState,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const SAMLResponse = res.data;
|
||||||
|
const redirectUri = res.data2.redirectUrl;
|
||||||
|
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -177,6 +189,10 @@ class AuthCallback extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (this.state.samlResponse !== "") {
|
||||||
|
return <RedirectForm samlResponse={this.state.samlResponse} redirectUrl={this.state.redirectUrl} relayState={this.state.relayState} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,7 @@ class CasLogout extends React.Component {
|
|||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
Setting.showMessage("success", "Logged out successfully");
|
Setting.showMessage("success", "Logged out successfully");
|
||||||
this.props.onUpdateAccount(null);
|
this.props.onUpdateAccount(null);
|
||||||
|
this.onUpdateApplication(null);
|
||||||
const redirectUri = res.data2;
|
const redirectUri = res.data2;
|
||||||
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
|
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
|
||||||
Setting.goToLink(redirectUri);
|
Setting.goToLink(redirectUri);
|
||||||
@ -49,6 +50,7 @@ class CasLogout extends React.Component {
|
|||||||
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
|
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
this.onUpdateApplication(null);
|
||||||
Setting.showMessage("error", `Failed to log out: ${res.msg}`);
|
Setting.showMessage("error", `Failed to log out: ${res.msg}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -102,6 +102,7 @@ class LoginPage extends React.Component {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Setting.showMessage("error", res.msg);
|
// Setting.showMessage("error", res.msg);
|
||||||
|
this.onUpdateApplication(null);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: res.data,
|
application: res.data,
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -133,6 +134,7 @@ class LoginPage extends React.Component {
|
|||||||
applicationName: res.data.name,
|
applicationName: res.data.name,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
this.onUpdateApplication(null);
|
||||||
Setting.showMessage("error", res.msg);
|
Setting.showMessage("error", res.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -318,15 +320,15 @@ class LoginPage extends React.Component {
|
|||||||
const accessToken = res.data;
|
const accessToken = res.data;
|
||||||
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`);
|
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`);
|
||||||
} else if (responseType === "saml") {
|
} else if (responseType === "saml") {
|
||||||
const SAMLResponse = res.data;
|
if (res.data2.method === "POST") {
|
||||||
const redirectUri = res.data2;
|
|
||||||
if (this.state.application.assertionConsumerUrl !== "") {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
samlResponse: res.data,
|
samlResponse: res.data,
|
||||||
redirectUrl: res.data2,
|
redirectUrl: res.data2.redirectUrl,
|
||||||
relayState: oAuthParams.relayState,
|
relayState: oAuthParams.relayState,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
const SAMLResponse = res.data;
|
||||||
|
const redirectUri = res.data2.redirectUrl;
|
||||||
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);
|
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -614,13 +616,13 @@ class LoginPage extends React.Component {
|
|||||||
this.sendSilentSigninData("signing-in");
|
this.sendSilentSigninData("signing-in");
|
||||||
|
|
||||||
const values = {};
|
const values = {};
|
||||||
values["application"] = this.state.application.name;
|
values["application"] = application.name;
|
||||||
this.onFinish(values);
|
this.onFinish(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application.enableAutoSignin) {
|
if (application.enableAutoSignin) {
|
||||||
const values = {};
|
const values = {};
|
||||||
values["application"] = this.state.application.name;
|
values["application"] = application.name;
|
||||||
this.onFinish(values);
|
this.onFinish(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +637,7 @@ class LoginPage extends React.Component {
|
|||||||
<br />
|
<br />
|
||||||
<SelfLoginButton account={this.props.account} onClick={() => {
|
<SelfLoginButton account={this.props.account} onClick={() => {
|
||||||
const values = {};
|
const values = {};
|
||||||
values["application"] = this.state.application.name;
|
values["application"] = application.name;
|
||||||
this.onFinish(values);
|
this.onFinish(values);
|
||||||
}} />
|
}} />
|
||||||
<br />
|
<br />
|
||||||
|
36
web/src/backend/SessionBackend.js
Normal file
36
web/src/backend/SessionBackend.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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 * as Setting from "../Setting";
|
||||||
|
|
||||||
|
export function getSessions(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/get-sessions?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": Setting.getAcceptLanguage(),
|
||||||
|
},
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteSession(session) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/delete-session`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(session),
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": Setting.getAcceptLanguage(),
|
||||||
|
},
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
@ -28,7 +28,7 @@ code {
|
|||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
background: url("https://cdn.casbin.org/img/casdoor-logo_1185x256.png");
|
background: url("https://cdn.casbin.org/img/casdoor-logo_1185x256.png");
|
||||||
background-size: 130px, 27px;
|
background-size: 130px, 27px !important;
|
||||||
width: 130px;
|
width: 130px;
|
||||||
height: 27px;
|
height: 27px;
|
||||||
margin: 17px 0 16px 15px;
|
margin: 17px 0 16px 15px;
|
||||||
@ -45,7 +45,3 @@ code {
|
|||||||
.ant-list-sm .ant-list-item {
|
.ant-list-sm .ant-list-item {
|
||||||
padding: 2px !important;
|
padding: 2px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-layout-header {
|
|
||||||
background-color: white !important;
|
|
||||||
}
|
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Click to Upload",
|
"Click to Upload": "Click to Upload",
|
||||||
"Client IP": "Client-IP",
|
"Client IP": "Client-IP",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "Erstellte Zeit",
|
"Created time": "Erstellte Zeit",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "Standard Avatar",
|
"Default avatar": "Standard Avatar",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "Speichern",
|
"Save": "Speichern",
|
||||||
"Save & Exit": "Speichern & Beenden",
|
"Save & Exit": "Speichern & Beenden",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "Anmelde-URL",
|
"Signin URL": "Anmelde-URL",
|
||||||
"Signin URL - Tooltip": "sign in url",
|
"Signin URL - Tooltip": "sign in url",
|
||||||
"Signup URL": "Registrierungs-URL",
|
"Signup URL": "Registrierungs-URL",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
|
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||||
"Is global admin": "Ist globaler Admin",
|
"Is global admin": "Ist globaler Admin",
|
||||||
"Is global admin - Tooltip": "Is the application global administrator",
|
"Is global admin - Tooltip": "Is the application global administrator",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "Link",
|
"Link": "Link",
|
||||||
"Location": "Standort",
|
"Location": "Standort",
|
||||||
"Location - Tooltip": "Standort - Tooltip",
|
"Location - Tooltip": "Standort - Tooltip",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "Passwort setzen",
|
"Password Set": "Passwort setzen",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "Eigenschaften",
|
"Properties": "Eigenschaften",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "Neu erneut eingeben",
|
"Re-enter New": "Neu erneut eingeben",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "Telefon zurücksetzen...",
|
"Reset Phone...": "Telefon zurücksetzen...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "Link aufheben",
|
"Unlink": "Link aufheben",
|
||||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||||
"Upload a photo": "Foto hochladen",
|
"Upload a photo": "Foto hochladen",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "Passwort eingeben"
|
"input password": "Passwort eingeben"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Click to Upload",
|
"Click to Upload": "Click to Upload",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "Signin URL",
|
"Signin URL": "Signin URL",
|
||||||
"Signin URL - Tooltip": "Signin URL - Tooltip",
|
"Signin URL - Tooltip": "Signin URL - Tooltip",
|
||||||
"Signup URL": "Signup URL",
|
"Signup URL": "Signup URL",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Is forbidden - Tooltip",
|
"Is forbidden - Tooltip": "Is forbidden - Tooltip",
|
||||||
"Is global admin": "Is global admin",
|
"Is global admin": "Is global admin",
|
||||||
"Is global admin - Tooltip": "Is global admin - Tooltip",
|
"Is global admin - Tooltip": "Is global admin - Tooltip",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "Link",
|
"Link": "Link",
|
||||||
"Location": "Location",
|
"Location": "Location",
|
||||||
"Location - Tooltip": "Location - Tooltip",
|
"Location - Tooltip": "Location - Tooltip",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "Password Set",
|
"Password Set": "Password Set",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "Properties",
|
"Properties": "Properties",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "Re-enter New",
|
"Re-enter New": "Re-enter New",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "Reset Phone...",
|
"Reset Phone...": "Reset Phone...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "Unlink",
|
"Unlink": "Unlink",
|
||||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||||
"Upload a photo": "Upload a photo",
|
"Upload a photo": "Upload a photo",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "input password"
|
"input password": "input password"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Click to Upload",
|
"Click to Upload": "Click to Upload",
|
||||||
"Client IP": "IP du client",
|
"Client IP": "IP du client",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "Date de création",
|
"Created time": "Date de création",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "Avatar par défaut",
|
"Default avatar": "Avatar par défaut",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "Enregistrer",
|
"Save": "Enregistrer",
|
||||||
"Save & Exit": "Enregistrer & Quitter",
|
"Save & Exit": "Enregistrer & Quitter",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "URL de connexion",
|
"Signin URL": "URL de connexion",
|
||||||
"Signin URL - Tooltip": "sign in url",
|
"Signin URL - Tooltip": "sign in url",
|
||||||
"Signup URL": "URL d'inscription",
|
"Signup URL": "URL d'inscription",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
|
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "Désolé, vous n'avez pas la permission d'accéder à cette page.",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||||
"Is global admin": "Est un administrateur global",
|
"Is global admin": "Est un administrateur global",
|
||||||
"Is global admin - Tooltip": "Is the application global administrator",
|
"Is global admin - Tooltip": "Is the application global administrator",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "Lier",
|
"Link": "Lier",
|
||||||
"Location": "Localisation",
|
"Location": "Localisation",
|
||||||
"Location - Tooltip": "Localisation - Infobulle",
|
"Location - Tooltip": "Localisation - Infobulle",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "Mot de passe défini",
|
"Password Set": "Mot de passe défini",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "Propriétés",
|
"Properties": "Propriétés",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "Nouvelle entrée",
|
"Re-enter New": "Nouvelle entrée",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "Réinitialiser le téléphone...",
|
"Reset Phone...": "Réinitialiser le téléphone...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "Délier",
|
"Unlink": "Délier",
|
||||||
"Upload (.xlsx)": "Télécharger (.xlsx)",
|
"Upload (.xlsx)": "Télécharger (.xlsx)",
|
||||||
"Upload a photo": "Télécharger une photo",
|
"Upload a photo": "Télécharger une photo",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "saisir le mot de passe"
|
"input password": "saisir le mot de passe"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Click to Upload",
|
"Click to Upload": "Click to Upload",
|
||||||
"Client IP": "クライアント IP",
|
"Client IP": "クライアント IP",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "作成日時",
|
"Created time": "作成日時",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "デフォルトのアバター",
|
"Default avatar": "デフォルトのアバター",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save & Exit": "保存して終了",
|
"Save & Exit": "保存して終了",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "サインインURL",
|
"Signin URL": "サインインURL",
|
||||||
"Signin URL - Tooltip": "sign in url",
|
"Signin URL - Tooltip": "sign in url",
|
||||||
"Signup URL": "サインアップURL",
|
"Signup URL": "サインアップURL",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
|
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "申し訳ありませんが、このページにアクセスする権限がありません。",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||||
"Is global admin": "グローバル管理者",
|
"Is global admin": "グローバル管理者",
|
||||||
"Is global admin - Tooltip": "Is the application global administrator",
|
"Is global admin - Tooltip": "Is the application global administrator",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "リンク",
|
"Link": "リンク",
|
||||||
"Location": "場所",
|
"Location": "場所",
|
||||||
"Location - Tooltip": "場所 → ツールチップ",
|
"Location - Tooltip": "場所 → ツールチップ",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "パスワード設定",
|
"Password Set": "パスワード設定",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "プロパティー",
|
"Properties": "プロパティー",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "新しい入力",
|
"Re-enter New": "新しい入力",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "電話番号をリセット...",
|
"Reset Phone...": "電話番号をリセット...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "リンクを解除",
|
"Unlink": "リンクを解除",
|
||||||
"Upload (.xlsx)": "アップロード (.xlsx)",
|
"Upload (.xlsx)": "アップロード (.xlsx)",
|
||||||
"Upload a photo": "写真をアップロード",
|
"Upload a photo": "写真をアップロード",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "パスワードを入力"
|
"input password": "パスワードを入力"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Click to Upload",
|
"Click to Upload": "Click to Upload",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "Signin URL",
|
"Signin URL": "Signin URL",
|
||||||
"Signin URL - Tooltip": "sign in url",
|
"Signin URL - Tooltip": "sign in url",
|
||||||
"Signup URL": "Signup URL",
|
"Signup URL": "Signup URL",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||||
"Is global admin": "Is global admin",
|
"Is global admin": "Is global admin",
|
||||||
"Is global admin - Tooltip": "Is the application global administrator",
|
"Is global admin - Tooltip": "Is the application global administrator",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "Link",
|
"Link": "Link",
|
||||||
"Location": "Location",
|
"Location": "Location",
|
||||||
"Location - Tooltip": "Location - Tooltip",
|
"Location - Tooltip": "Location - Tooltip",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "Password Set",
|
"Password Set": "Password Set",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "Properties",
|
"Properties": "Properties",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "Re-enter New",
|
"Re-enter New": "Re-enter New",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "Reset Phone...",
|
"Reset Phone...": "Reset Phone...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "Unlink",
|
"Unlink": "Unlink",
|
||||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||||
"Upload a photo": "Upload a photo",
|
"Upload a photo": "Upload a photo",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "input password"
|
"input password": "input password"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "Нажмите здесь, чтобы загрузить",
|
"Click to Upload": "Нажмите здесь, чтобы загрузить",
|
||||||
"Client IP": "IP клиента",
|
"Client IP": "IP клиента",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
|
"Compact": "Compact",
|
||||||
"Created time": "Время создания",
|
"Created time": "Время создания",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Default": "Default",
|
||||||
"Default application": "Default application",
|
"Default application": "Default application",
|
||||||
"Default application - Tooltip": "Default application - Tooltip",
|
"Default application - Tooltip": "Default application - Tooltip",
|
||||||
"Default avatar": "Аватар по умолчанию",
|
"Default avatar": "Аватар по умолчанию",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "Roles - Tooltip",
|
"Roles - Tooltip": "Roles - Tooltip",
|
||||||
"Save": "Сохранить",
|
"Save": "Сохранить",
|
||||||
"Save & Exit": "Сохранить и выйти",
|
"Save & Exit": "Сохранить и выйти",
|
||||||
|
"Session ID": "Session ID",
|
||||||
|
"Sessions": "Sessions",
|
||||||
"Signin URL": "URL входа",
|
"Signin URL": "URL входа",
|
||||||
"Signin URL - Tooltip": "sign in url",
|
"Signin URL - Tooltip": "sign in url",
|
||||||
"Signup URL": "URL регистрации",
|
"Signup URL": "URL регистрации",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||||
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
|
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
|
||||||
"Sorry, you do not have permission to access this page.": "Извините, вы не имеете права доступа к этой странице.",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
|
||||||
"State": "State",
|
"State": "State",
|
||||||
"State - Tooltip": "State - Tooltip",
|
"State - Tooltip": "State - Tooltip",
|
||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||||
"Is global admin": "Глобальный администратор",
|
"Is global admin": "Глобальный администратор",
|
||||||
"Is global admin - Tooltip": "Is the application global administrator",
|
"Is global admin - Tooltip": "Is the application global administrator",
|
||||||
|
"Keys": "Keys",
|
||||||
"Link": "Ссылка",
|
"Link": "Ссылка",
|
||||||
"Location": "Местоположение",
|
"Location": "Местоположение",
|
||||||
"Location - Tooltip": "Расположение - Подсказка",
|
"Location - Tooltip": "Расположение - Подсказка",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "Пароль установлен",
|
"Password Set": "Пароль установлен",
|
||||||
"Please select avatar from resources": "Please select avatar from resources",
|
"Please select avatar from resources": "Please select avatar from resources",
|
||||||
"Properties": "Свойства",
|
"Properties": "Свойства",
|
||||||
|
"Properties - Tooltip": "Properties - Tooltip",
|
||||||
"Re-enter New": "Введите еще раз",
|
"Re-enter New": "Введите еще раз",
|
||||||
"Reset Email...": "Reset Email...",
|
"Reset Email...": "Reset Email...",
|
||||||
"Reset Phone...": "Сбросить телефон...",
|
"Reset Phone...": "Сбросить телефон...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "Отвязать",
|
"Unlink": "Отвязать",
|
||||||
"Upload (.xlsx)": "Загрузить (.xlsx)",
|
"Upload (.xlsx)": "Загрузить (.xlsx)",
|
||||||
"Upload a photo": "Загрузить фото",
|
"Upload a photo": "Загрузить фото",
|
||||||
|
"Values": "Values",
|
||||||
"WebAuthn credentials": "WebAuthn credentials",
|
"WebAuthn credentials": "WebAuthn credentials",
|
||||||
"input password": "пароль для ввода"
|
"input password": "пароль для ввода"
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,10 @@
|
|||||||
"Click to Upload": "点击上传",
|
"Click to Upload": "点击上传",
|
||||||
"Client IP": "客户端IP",
|
"Client IP": "客户端IP",
|
||||||
"Close": "关闭",
|
"Close": "关闭",
|
||||||
|
"Compact": "紧凑",
|
||||||
"Created time": "创建时间",
|
"Created time": "创建时间",
|
||||||
|
"Dark": "黑暗",
|
||||||
|
"Default": "默认",
|
||||||
"Default application": "默认应用",
|
"Default application": "默认应用",
|
||||||
"Default application - Tooltip": "默认应用",
|
"Default application - Tooltip": "默认应用",
|
||||||
"Default avatar": "默认头像",
|
"Default avatar": "默认头像",
|
||||||
@ -233,6 +236,8 @@
|
|||||||
"Roles - Tooltip": "角色",
|
"Roles - Tooltip": "角色",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save & Exit": "保存 & 退出",
|
"Save & Exit": "保存 & 退出",
|
||||||
|
"Session ID": "会话 ID",
|
||||||
|
"Sessions": "会话",
|
||||||
"Signin URL": "登录URL",
|
"Signin URL": "登录URL",
|
||||||
"Signin URL - Tooltip": "用户的登录地址",
|
"Signin URL - Tooltip": "用户的登录地址",
|
||||||
"Signup URL": "注册URL",
|
"Signup URL": "注册URL",
|
||||||
@ -241,7 +246,7 @@
|
|||||||
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
|
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
|
||||||
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
|
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
|
||||||
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "抱歉,您访问的用户不存在或您无权访问该用户",
|
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "抱歉,您访问的用户不存在或您无权访问该用户",
|
||||||
"Sorry, you do not have permission to access this page.": "抱歉,您无权访问该页面",
|
"Sorry, you do not have permission to access this page or logged in status invalid.": "抱歉,您无权访问该页面或登录状态失效",
|
||||||
"State": "状态",
|
"State": "状态",
|
||||||
"State - Tooltip": "状态",
|
"State - Tooltip": "状态",
|
||||||
"Successfully added": "添加成功",
|
"Successfully added": "添加成功",
|
||||||
@ -723,6 +728,7 @@
|
|||||||
"Is forbidden - Tooltip": "账户是否已被禁用",
|
"Is forbidden - Tooltip": "账户是否已被禁用",
|
||||||
"Is global admin": "是全局管理员",
|
"Is global admin": "是全局管理员",
|
||||||
"Is global admin - Tooltip": "是应用程序管理员",
|
"Is global admin - Tooltip": "是应用程序管理员",
|
||||||
|
"Keys": "键",
|
||||||
"Link": "绑定",
|
"Link": "绑定",
|
||||||
"Location": "城市",
|
"Location": "城市",
|
||||||
"Location - Tooltip": "居住地址所在的城市",
|
"Location - Tooltip": "居住地址所在的城市",
|
||||||
@ -738,6 +744,7 @@
|
|||||||
"Password Set": "密码已设置",
|
"Password Set": "密码已设置",
|
||||||
"Please select avatar from resources": "从资源中选择...",
|
"Please select avatar from resources": "从资源中选择...",
|
||||||
"Properties": "属性",
|
"Properties": "属性",
|
||||||
|
"Properties - Tooltip": "属性",
|
||||||
"Re-enter New": "重复新密码",
|
"Re-enter New": "重复新密码",
|
||||||
"Reset Email...": "重置邮箱...",
|
"Reset Email...": "重置邮箱...",
|
||||||
"Reset Phone...": "重置手机号...",
|
"Reset Phone...": "重置手机号...",
|
||||||
@ -753,6 +760,7 @@
|
|||||||
"Unlink": "解绑",
|
"Unlink": "解绑",
|
||||||
"Upload (.xlsx)": "上传(.xlsx)",
|
"Upload (.xlsx)": "上传(.xlsx)",
|
||||||
"Upload a photo": "上传头像",
|
"Upload a photo": "上传头像",
|
||||||
|
"Values": "值",
|
||||||
"WebAuthn credentials": "WebAuthn凭据",
|
"WebAuthn credentials": "WebAuthn凭据",
|
||||||
"input password": "输入密码"
|
"input password": "输入密码"
|
||||||
},
|
},
|
||||||
|
131
web/src/propertyTable.js
Normal file
131
web/src/propertyTable.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// 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 React from "react";
|
||||||
|
import {Button, Input, Table} from "antd";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import {DeleteOutlined} from "@ant-design/icons";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
|
||||||
|
class PropertyTable extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
properties: [],
|
||||||
|
count: Object.entries(this.props.properties).length,
|
||||||
|
};
|
||||||
|
// transfer the Object to object[]
|
||||||
|
Object.entries(this.props.properties).map((item, index) => {
|
||||||
|
this.state.properties.push({key: index, name: item[0], value: item[1]});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
page = 1;
|
||||||
|
|
||||||
|
updateTable(table) {
|
||||||
|
this.setState({properties: table});
|
||||||
|
const properties = {};
|
||||||
|
table.map((item) => {
|
||||||
|
properties[item.name] = item.value;
|
||||||
|
});
|
||||||
|
this.props.onUpdateTable(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
addRow(table) {
|
||||||
|
const row = {key: this.state.count, name: "", value: ""};
|
||||||
|
if (table === undefined) {
|
||||||
|
table = [];
|
||||||
|
}
|
||||||
|
table = Setting.addRow(table, row);
|
||||||
|
this.setState({count: this.state.count + 1});
|
||||||
|
this.updateTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRow(table, index) {
|
||||||
|
table = Setting.deleteRow(table, this.getIndex(index));
|
||||||
|
this.updateTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndex(index) {
|
||||||
|
// Parameter is the row index in table, need to calculate the index in dataSource. 10 is the pageSize.
|
||||||
|
return index + (this.page - 1) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateField(table, index, key, value) {
|
||||||
|
table[this.getIndex(index)][key] = value;
|
||||||
|
this.updateTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(table) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: i18next.t("user:Keys"),
|
||||||
|
dataIndex: "name",
|
||||||
|
width: "200px",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Input value={text} onChange={e => {
|
||||||
|
this.updateField(table, index, "name", e.target.value);
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("user:Values"),
|
||||||
|
dataIndex: "value",
|
||||||
|
width: "200px",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Input value={text} onChange={e => {
|
||||||
|
this.updateField(table, index, "value", e.target.value);
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Action"),
|
||||||
|
dataIndex: "operation",
|
||||||
|
width: "20px",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table title={() => (
|
||||||
|
<div>
|
||||||
|
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
pagination={{onChange: page => {this.page = page;}}}
|
||||||
|
columns={columns} dataSource={table} rowKey="key" size="middle" bordered
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{
|
||||||
|
this.renderTable(this.state.properties)
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PropertyTable;
|
23344
web/yarn.lock
23344
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user