mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-10 10:15:19 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
d498bc60ce | |||
7bbe1e38c1 | |||
f465fc6ce0 | |||
c952c2f2f4 | |||
86ae97d1e5 | |||
6ea73e3eca | |||
a71a190db5 | |||
da69d94445 | |||
b8b915abe1 | |||
5d1548e989 | |||
a0dc6e06cd | |||
ae130788ec | |||
f075d0fd74 |
@ -170,7 +170,7 @@ func (c *ApiController) GetApplicationLogin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setHttpClient(idProvider idp.IdProvider, providerType string) {
|
func setHttpClient(idProvider idp.IdProvider, providerType string) {
|
||||||
if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" || providerType == "Steam" {
|
if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" || providerType == "Steam" || providerType == "Line" {
|
||||||
idProvider.SetHttpClient(proxy.ProxyHttpClient)
|
idProvider.SetHttpClient(proxy.ProxyHttpClient)
|
||||||
} else {
|
} else {
|
||||||
idProvider.SetHttpClient(proxy.DefaultHttpClient)
|
idProvider.SetHttpClient(proxy.DefaultHttpClient)
|
||||||
@ -265,6 +265,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)
|
||||||
|
@ -261,7 +261,7 @@ func (c *ApiController) TokenLogout() {
|
|||||||
flag, application := object.DeleteTokenByAccessToken(token)
|
flag, application := object.DeleteTokenByAccessToken(token)
|
||||||
redirectUri := c.Input().Get("post_logout_redirect_uri")
|
redirectUri := c.Input().Get("post_logout_redirect_uri")
|
||||||
state := c.Input().Get("state")
|
state := c.Input().Get("state")
|
||||||
if application != nil && object.CheckRedirectUriValid(application, redirectUri) {
|
if application != nil && application.IsRedirectUriValid(redirectUri) {
|
||||||
c.Ctx.Redirect(http.StatusFound, redirectUri+"?state="+state)
|
c.Ctx.Redirect(http.StatusFound, redirectUri+"?state="+state)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -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 不匹配"
|
||||||
|
@ -98,7 +98,7 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var gothList = []string{"Apple", "AzureAD", "Slack", "Steam"}
|
var gothList = []string{"Apple", "AzureAD", "Slack", "Steam", "Line"}
|
||||||
|
|
||||||
func isGothSupport(provider string) bool {
|
func isGothSupport(provider string) bool {
|
||||||
for _, value := range gothList {
|
for _, value := range gothList {
|
||||||
|
@ -16,7 +16,6 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -354,54 +353,28 @@ func (application *Application) GetId() string {
|
|||||||
return fmt.Sprintf("%s/%s", application.Owner, application.Name)
|
return fmt.Sprintf("%s/%s", application.Owner, application.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckRedirectUriValid(application *Application, redirectUri string) bool {
|
func (application *Application) IsRedirectUriValid(redirectUri string) bool {
|
||||||
validUri := false
|
isValid := false
|
||||||
for _, tmpUri := range application.RedirectUris {
|
for _, targetUri := range application.RedirectUris {
|
||||||
tmpUriRegex := regexp.MustCompile(tmpUri)
|
targetUriRegex := regexp.MustCompile(targetUri)
|
||||||
if tmpUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, tmpUri) {
|
if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) {
|
||||||
validUri = true
|
isValid = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return validUri
|
return isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsAllowOrigin(origin string) bool {
|
func IsOriginAllowed(origin string) bool {
|
||||||
allowOrigin := false
|
applications := GetApplications("")
|
||||||
originUrl, err := url.Parse(origin)
|
for _, application := range applications {
|
||||||
if err != nil {
|
if application.IsRedirectUriValid(origin) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := adapter.Engine.Cols("redirect_uris").Rows(&Application{})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
application := Application{}
|
|
||||||
for rows.Next() {
|
|
||||||
err := rows.Scan(&application)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for _, tmpRedirectUri := range application.RedirectUris {
|
|
||||||
u1, err := url.Parse(tmpRedirectUri)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if u1.Scheme == originUrl.Scheme && u1.Host == originUrl.Host {
|
|
||||||
allowOrigin = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if allowOrigin {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allowOrigin
|
|
||||||
}
|
|
||||||
|
|
||||||
func getApplicationMap(organization string) map[string]*Application {
|
func getApplicationMap(organization string) map[string]*Application {
|
||||||
applications := GetOrganizationApplications("admin", organization)
|
applications := GetOrganizationApplications("admin", organization)
|
||||||
|
|
||||||
|
@ -313,8 +313,9 @@ func CheckAccessPermission(userId string, application *Application) (bool, error
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
enforcer := getEnforcer(permission)
|
enforcer := getEnforcer(permission)
|
||||||
allowed, err = enforcer.Enforce(userId, application.Name, "read")
|
if allowed, err = enforcer.Enforce(userId, application.Name, "read"); allowed {
|
||||||
break
|
return allowed, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allowed, err
|
return allowed, err
|
||||||
|
@ -240,8 +240,8 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verify samlRequest
|
// verify samlRequest
|
||||||
if valid := CheckRedirectUriValid(application, authnRequest.Issuer.Url); !valid {
|
if isValid := application.IsRedirectUriValid(authnRequest.Issuer.Url); !isValid {
|
||||||
return "", "", fmt.Errorf("err: invalid issuer url")
|
return "", "", fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer.Url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get certificate string
|
// get certificate string
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/i18n"
|
"github.com/casdoor/casdoor/i18n"
|
||||||
@ -253,14 +252,7 @@ func CheckOAuthLogin(clientId string, responseType string, redirectUri string, s
|
|||||||
return i18n.Translate(lang, "token:Invalid client_id"), nil
|
return i18n.Translate(lang, "token:Invalid client_id"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
validUri := false
|
if !application.IsRedirectUriValid(redirectUri) {
|
||||||
for _, tmpUri := range application.RedirectUris {
|
|
||||||
if strings.Contains(redirectUri, tmpUri) {
|
|
||||||
validUri = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !validUri {
|
|
||||||
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application
|
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ type User struct {
|
|||||||
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
|
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
|
||||||
Okta string `xorm:"okta varchar(100)" json:"okta"`
|
Okta string `xorm:"okta varchar(100)" json:"okta"`
|
||||||
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
|
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
|
||||||
|
Line string `xorm:"line varchar(100)" json:"line"`
|
||||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||||
|
|
||||||
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
||||||
|
@ -34,7 +34,7 @@ func CorsFilter(ctx *context.Context) {
|
|||||||
originConf := conf.GetConfigString("origin")
|
originConf := conf.GetConfigString("origin")
|
||||||
|
|
||||||
if origin != "" && originConf != "" && origin != originConf {
|
if origin != "" && originConf != "" && origin != originConf {
|
||||||
if object.IsAllowOrigin(origin) {
|
if object.IsOriginAllowed(origin) {
|
||||||
ctx.Output.Header(headerAllowOrigin, origin)
|
ctx.Output.Header(headerAllowOrigin, origin)
|
||||||
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS")
|
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS")
|
||||||
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
|
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
|
||||||
|
105
web/src/App.js
105
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";
|
||||||
@ -55,26 +55,21 @@ import CustomGithubCorner from "./CustomGithubCorner";
|
|||||||
import * as Conf from "./Conf";
|
import * as Conf from "./Conf";
|
||||||
|
|
||||||
import * as Auth from "./auth/Auth";
|
import * as Auth from "./auth/Auth";
|
||||||
import SignupPage from "./auth/SignupPage";
|
import EntryPage from "./EntryPage";
|
||||||
import ResultPage from "./auth/ResultPage";
|
import ResultPage from "./auth/ResultPage";
|
||||||
import LoginPage from "./auth/LoginPage";
|
|
||||||
import SelfLoginPage from "./auth/SelfLoginPage";
|
|
||||||
import SelfForgetPage from "./auth/SelfForgetPage";
|
|
||||||
import ForgetPage from "./auth/ForgetPage";
|
|
||||||
import * as AuthBackend from "./auth/AuthBackend";
|
import * as AuthBackend from "./auth/AuthBackend";
|
||||||
import AuthCallback from "./auth/AuthCallback";
|
import AuthCallback from "./auth/AuthCallback";
|
||||||
import SelectLanguageBox from "./SelectLanguageBox";
|
import SelectLanguageBox from "./SelectLanguageBox";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import PromptPage from "./auth/PromptPage";
|
|
||||||
import OdicDiscoveryPage from "./auth/OidcDiscoveryPage";
|
import OdicDiscoveryPage from "./auth/OidcDiscoveryPage";
|
||||||
import SamlCallback from "./auth/SamlCallback";
|
import SamlCallback from "./auth/SamlCallback";
|
||||||
import CasLogout from "./auth/CasLogout";
|
|
||||||
import ModelListPage from "./ModelListPage";
|
import ModelListPage from "./ModelListPage";
|
||||||
import ModelEditPage from "./ModelEditPage";
|
import ModelEditPage from "./ModelEditPage";
|
||||||
import SystemInfo from "./SystemInfo";
|
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";
|
||||||
|
|
||||||
const {Header, Footer, Content} = Layout;
|
const {Header, Footer, Content} = Layout;
|
||||||
|
|
||||||
@ -87,6 +82,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();
|
||||||
@ -101,6 +98,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;
|
||||||
@ -190,6 +197,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) {
|
||||||
@ -471,6 +482,13 @@ class App extends Component {
|
|||||||
|
|
||||||
renderRouter() {
|
renderRouter() {
|
||||||
return (
|
return (
|
||||||
|
<ConfigProvider theme={{
|
||||||
|
token: {
|
||||||
|
colorPrimary: "rgb(89,54,213)",
|
||||||
|
colorInfo: "rgb(89,54,213)",
|
||||||
|
},
|
||||||
|
algorithm: this.state.themeAlgorithm,
|
||||||
|
}}>
|
||||||
<div>
|
<div>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...props} />)} />
|
||||||
@ -519,6 +537,7 @@ class App extends Component {
|
|||||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,30 +557,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
|
||||||
// theme="dark"
|
|
||||||
items={this.renderMenu()}
|
items={this.renderMenu()}
|
||||||
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
||||||
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
||||||
style={{lineHeight: "64px", position: "absolute", left: "145px", right: "200px"}}
|
style={{position: "absolute", left: "145px", backgroundColor: this.state.themeAlgorithm === theme.darkAlgorithm ? "black" : "white"}}
|
||||||
>
|
/>
|
||||||
</Menu>
|
|
||||||
{
|
{
|
||||||
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={{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()
|
||||||
@ -576,11 +592,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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -598,12 +614,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()}
|
||||||
@ -619,74 +634,66 @@ class App extends Component {
|
|||||||
// https://www.freecodecamp.org/neyarnws/how-to-keep-your-footer-where-it-belongs-59c6aa05c59c/
|
// https://www.freecodecamp.org/neyarnws/how-to-keep-your-footer-where-it-belongs-59c6aa05c59c/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<React.Fragment>
|
||||||
{!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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
isDoorPages() {
|
isDoorPages() {
|
||||||
|
return this.isEntryPages() || window.location.pathname.startsWith("/callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
isEntryPages() {
|
||||||
return window.location.pathname.startsWith("/signup") ||
|
return window.location.pathname.startsWith("/signup") ||
|
||||||
window.location.pathname.startsWith("/login") ||
|
window.location.pathname.startsWith("/login") ||
|
||||||
window.location.pathname.startsWith("/callback") ||
|
|
||||||
window.location.pathname.startsWith("/prompt") ||
|
|
||||||
window.location.pathname.startsWith("/forget") ||
|
window.location.pathname.startsWith("/forget") ||
|
||||||
window.location.pathname.startsWith("/cas");
|
window.location.pathname.startsWith("/prompt") ||
|
||||||
|
window.location.pathname.startsWith("/cas") ||
|
||||||
|
window.location.pathname.startsWith("/auto-signup");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPage() {
|
renderPage() {
|
||||||
if (this.isDoorPages()) {
|
if (this.isDoorPages()) {
|
||||||
return (
|
return (
|
||||||
<>
|
<React.Fragment>
|
||||||
<Layout id="parent-area">
|
<Layout id="parent-area">
|
||||||
<Content style={{display: "flex", justifyContent: "center"}}>
|
<Content style={{display: "flex", justifyContent: "center"}}>
|
||||||
|
{
|
||||||
|
this.isEntryPages() ?
|
||||||
|
<EntryPage account={this.state.account} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />
|
||||||
|
:
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />)} />
|
|
||||||
<Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/login/:owner" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/auto-signup/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signup"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
|
|
||||||
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
|
|
||||||
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
|
|
||||||
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage account={this.state.account} type={"saml"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
|
|
||||||
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout clearAccount={() => this.setState({account: null})} {...props} />)} />
|
|
||||||
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage type={"cas"} mode={"signup"} account={this.state.account} {...props} />);}} />
|
|
||||||
<Route exact path="/callback" component={AuthCallback} />
|
<Route exact path="/callback" component={AuthCallback} />
|
||||||
<Route exact path="/callback/saml" component={SamlCallback} />
|
<Route exact path="/callback/saml" component={SamlCallback} />
|
||||||
<Route exact path="/forget" render={(props) => this.renderHomeIfLoggedIn(<SelfForgetPage {...props} />)} />
|
|
||||||
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...props} />)} />
|
|
||||||
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage account={this.state.account} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} {...props} />)} />
|
|
||||||
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo {...props} />)} />
|
|
||||||
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
||||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
}
|
||||||
</Content>
|
</Content>
|
||||||
{
|
{
|
||||||
this.renderFooter()
|
this.renderFooter()
|
||||||
}
|
}
|
||||||
</Layout>
|
</Layout>
|
||||||
</>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<React.Fragment>
|
||||||
<FloatButton.BackTop />
|
<FloatButton.BackTop />
|
||||||
<CustomGithubCorner />
|
<CustomGithubCorner />
|
||||||
{
|
{
|
||||||
this.renderContent()
|
this.renderContent()
|
||||||
}
|
}
|
||||||
</>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,6 +709,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()
|
||||||
@ -723,6 +731,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;
|
||||||
|
}
|
||||||
|
@ -726,7 +726,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
renderSignupSigninPreview() {
|
renderSignupSigninPreview() {
|
||||||
let signUpUrl = `/signup/${this.state.application.name}`;
|
let signUpUrl = `/signup/${this.state.application.name}`;
|
||||||
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`;
|
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`;
|
||||||
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||||
if (!this.state.application.enablePassword) {
|
if (!this.state.application.enablePassword) {
|
||||||
signUpUrl = signInUrl.replace("/login/oauth/authorize", "/signup/oauth/authorize");
|
signUpUrl = signInUrl.replace("/login/oauth/authorize", "/signup/oauth/authorize");
|
||||||
}
|
}
|
||||||
@ -742,15 +742,19 @@ class ApplicationEditPage extends React.Component {
|
|||||||
{i18next.t("application:Copy signup page URL")}
|
{i18next.t("application:Copy signup page URL")}
|
||||||
</Button>
|
</Button>
|
||||||
<br />
|
<br />
|
||||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", overflow: "auto"}}>
|
||||||
{
|
{
|
||||||
this.state.application.enablePassword ? (
|
this.state.application.enablePassword ? (
|
||||||
<SignupPage application={this.state.application} />
|
<div className="loginBackground" style={{backgroundImage: `url(${this.state.application?.formBackgroundUrl})`, overflow: "auto"}}>
|
||||||
|
<SignupPage application={this.state.application} preview = "auto" />
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<LoginPage type={"login"} mode={"signup"} application={this.state.application} />
|
<div className="loginBackground" style={{backgroundImage: `url(${this.state.application?.formBackgroundUrl})`, overflow: "auto"}}>
|
||||||
|
<LoginPage type={"login"} mode={"signup"} application={this.state.application} preview = "auto" />
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div style={maskStyle} />
|
<div style={{overflow: "auto", ...maskStyle}} />
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={previewGrid}>
|
<Col span={previewGrid}>
|
||||||
@ -762,9 +766,11 @@ class ApplicationEditPage extends React.Component {
|
|||||||
{i18next.t("application:Copy signin page URL")}
|
{i18next.t("application:Copy signin page URL")}
|
||||||
</Button>
|
</Button>
|
||||||
<br />
|
<br />
|
||||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", overflow: "auto"}}>
|
||||||
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
|
<div className="loginBackground" style={{backgroundImage: `url(${this.state.application?.formBackgroundUrl})`, overflow: "auto"}}>
|
||||||
<div style={maskStyle} />
|
<LoginPage type={"login"} mode={"signin"} application={this.state.application} preview = "auto" />
|
||||||
|
</div>
|
||||||
|
<div style={{overflow: "auto", ...maskStyle}} />
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
84
web/src/EntryPage.js
Normal file
84
web/src/EntryPage.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// 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 {Redirect, Route, Switch} from "react-router-dom";
|
||||||
|
import {Spin} from "antd";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import SignupPage from "./auth/SignupPage";
|
||||||
|
import SelfLoginPage from "./auth/SelfLoginPage";
|
||||||
|
import LoginPage from "./auth/LoginPage";
|
||||||
|
import SelfForgetPage from "./auth/SelfForgetPage";
|
||||||
|
import ForgetPage from "./auth/ForgetPage";
|
||||||
|
import PromptPage from "./auth/PromptPage";
|
||||||
|
import CasLogout from "./auth/CasLogout";
|
||||||
|
|
||||||
|
class EntryPage extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
application: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHomeIfLoggedIn(component) {
|
||||||
|
if (this.props.account !== null && this.props.account !== undefined) {
|
||||||
|
return <Redirect to="/" />;
|
||||||
|
} else {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoginIfNotLoggedIn(component) {
|
||||||
|
if (this.props.account === null) {
|
||||||
|
sessionStorage.setItem("from", window.location.pathname);
|
||||||
|
return <Redirect to="/login" />;
|
||||||
|
} else if (this.props.account === undefined) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const onUpdateApplication = (application) => {
|
||||||
|
this.setState({
|
||||||
|
application: application,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div className="loginBackground" style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${this.state.application?.formBackgroundUrl})`}}>
|
||||||
|
<Spin spinning={this.state.application === undefined} tip={i18next.t("login:Loading")} style={{margin: "0 auto"}} />
|
||||||
|
<Switch>
|
||||||
|
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/login/:owner" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/auto-signup/oauth/authorize" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"code"} mode={"signup"} onUpdateApplication={onUpdateApplication}{...props} />} />
|
||||||
|
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
|
||||||
|
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"code"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
|
||||||
|
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"saml"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
|
||||||
|
<Route exact path="/forget" render={(props) => this.renderHomeIfLoggedIn(<SelfForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
|
||||||
|
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} {...props} />)} />
|
||||||
|
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signup"} {...props} />);}} />
|
||||||
|
</Switch>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EntryPage;
|
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;
|
@ -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: "Dark", key: "Dark", style: darkAlgorithm, selectThemeLogo: `${StaticBaseUrl}/img/dark.svg`},
|
||||||
|
{label: "Compact", key: "Compact", style: compactAlgorithm, selectThemeLogo: `${StaticBaseUrl}/img/compact.svg`},
|
||||||
|
{label: "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";
|
||||||
@ -681,6 +701,7 @@ export function getProviderTypeOptions(category) {
|
|||||||
{id: "Bilibili", name: "Bilibili"},
|
{id: "Bilibili", name: "Bilibili"},
|
||||||
{id: "Okta", name: "Okta"},
|
{id: "Okta", name: "Okta"},
|
||||||
{id: "Douyin", name: "Douyin"},
|
{id: "Douyin", name: "Douyin"},
|
||||||
|
{id: "Line", name: "Line"},
|
||||||
{id: "Custom", name: "Custom"},
|
{id: "Custom", name: "Custom"},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -798,6 +819,9 @@ export function renderLoginLink(application, text) {
|
|||||||
|
|
||||||
export function redirectToLoginPage(application, history) {
|
export function redirectToLoginPage(application, history) {
|
||||||
const loginLink = getLoginLink(application);
|
const loginLink = getLoginLink(application);
|
||||||
|
if (loginLink.indexOf("http") === 0 || loginLink.indexOf("https") === 0) {
|
||||||
|
window.location.replace(loginLink);
|
||||||
|
}
|
||||||
history.push(loginLink);
|
history.push(loginLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -178,7 +178,7 @@ class AuthCallback extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign: "center"}}>
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
{
|
{
|
||||||
(this.state.msg === null) ? (
|
(this.state.msg === null) ? (
|
||||||
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Spin} from "antd";
|
import {Card, Spin} from "antd";
|
||||||
import {withRouter} from "react-router-dom";
|
import {withRouter} from "react-router-dom";
|
||||||
import * as AuthBackend from "./AuthBackend";
|
import * as AuthBackend from "./AuthBackend";
|
||||||
import * as Setting from "../Setting";
|
import * as Setting from "../Setting";
|
||||||
@ -39,7 +39,8 @@ class CasLogout extends React.Component {
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
Setting.showMessage("success", "Logged out successfully");
|
Setting.showMessage("success", "Logged out successfully");
|
||||||
this.props.clearAccount();
|
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}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -57,11 +59,13 @@ class CasLogout extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign: "center"}}>
|
<Card>
|
||||||
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
{
|
{
|
||||||
<Spin size="large" tip={i18next.t("login:Logging out...")} style={{paddingTop: "10%"}} />
|
<Spin size="large" tip={i18next.t("login:Logging out...")} style={{paddingTop: "10%"}} />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,7 @@ class ForgetPage extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
account: props.account,
|
account: props.account,
|
||||||
applicationName:
|
applicationName: props.applicationName ?? props.match.params?.applicationName,
|
||||||
props.applicationName !== undefined
|
|
||||||
? props.applicationName
|
|
||||||
: props.match === undefined
|
|
||||||
? null
|
|
||||||
: props.match.params.applicationName,
|
|
||||||
application: null,
|
application: null,
|
||||||
msg: null,
|
msg: null,
|
||||||
userId: "",
|
userId: "",
|
||||||
@ -57,34 +52,36 @@ class ForgetPage extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
componentDidMount() {
|
||||||
|
if (this.getApplicationObj() === null) {
|
||||||
if (this.state.applicationName !== undefined) {
|
if (this.state.applicationName !== undefined) {
|
||||||
this.getApplication();
|
this.getApplication();
|
||||||
} else {
|
} else {
|
||||||
Setting.showMessage("error", i18next.t("forget:Unknown forget type: ") + this.state.type);
|
Setting.showMessage("error", i18next.t("forget:Unknown forget type: ") + this.state.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getApplication() {
|
getApplication() {
|
||||||
if (this.state.applicationName === null) {
|
if (this.state.applicationName === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationBackend.getApplication("admin", this.state.applicationName).then(
|
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
||||||
(application) => {
|
.then((application) => {
|
||||||
|
this.onUpdateApplication(application);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationObj() {
|
getApplicationObj() {
|
||||||
if (this.props.application !== undefined) {
|
return this.props.application ?? this.state.application;
|
||||||
return this.props.application;
|
|
||||||
} else {
|
|
||||||
return this.state.application;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateApplication(application) {
|
||||||
|
this.props.onUpdateApplication(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
onFormFinish(name, info, forms) {
|
onFormFinish(name, info, forms) {
|
||||||
@ -143,7 +140,7 @@ class ForgetPage extends React.Component {
|
|||||||
username: this.state.username,
|
username: this.state.username,
|
||||||
name: this.state.name,
|
name: this.state.name,
|
||||||
code: forms.step2.getFieldValue("emailCode"),
|
code: forms.step2.getFieldValue("emailCode"),
|
||||||
phonePrefix: this.state.application?.organizationObj.phonePrefix,
|
phonePrefix: this.getApplicationObj()?.organizationObj.phonePrefix,
|
||||||
type: "login",
|
type: "login",
|
||||||
}, oAuthParams).then(res => {
|
}, oAuthParams).then(res => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
@ -166,10 +163,10 @@ class ForgetPage extends React.Component {
|
|||||||
|
|
||||||
onFinish(values) {
|
onFinish(values) {
|
||||||
values.username = this.state.username;
|
values.username = this.state.username;
|
||||||
values.userOwner = this.state.application?.organizationObj.name;
|
values.userOwner = this.getApplicationObj()?.organizationObj.name;
|
||||||
UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => {
|
UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
Setting.redirectToLoginPage(this.state.application, this.props.history);
|
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
|
||||||
} else {
|
} else {
|
||||||
Setting.showMessage("error", i18next.t(`signup:${res.msg}`));
|
Setting.showMessage("error", i18next.t(`signup:${res.msg}`));
|
||||||
}
|
}
|
||||||
@ -356,14 +353,14 @@ class ForgetPage extends React.Component {
|
|||||||
<CountDownInput
|
<CountDownInput
|
||||||
disabled={this.state.username === "" || this.state.verifyType === ""}
|
disabled={this.state.username === "" || this.state.verifyType === ""}
|
||||||
method={"forget"}
|
method={"forget"}
|
||||||
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.state.application), this.state.name]}
|
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
|
||||||
application={application}
|
application={application}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CountDownInput
|
<CountDownInput
|
||||||
disabled={this.state.username === "" || this.state.verifyType === ""}
|
disabled={this.state.username === "" || this.state.verifyType === ""}
|
||||||
method={"forget"}
|
method={"forget"}
|
||||||
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.state.application), this.state.name]}
|
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
|
||||||
application={application}
|
application={application}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -492,7 +489,7 @@ class ForgetPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="loginBackground" style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${application.formBackgroundUrl})`}}>
|
<React.Fragment>
|
||||||
<CustomGithubCorner />
|
<CustomGithubCorner />
|
||||||
<div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}>
|
<div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}>
|
||||||
<Row>
|
<Row>
|
||||||
@ -550,7 +547,7 @@ class ForgetPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
web/src/auth/LineLoginButton.js
Normal file
32
web/src/auth/LineLoginButton.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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 {createButton} from "react-social-login-buttons";
|
||||||
|
import {StaticBaseUrl} from "../Setting";
|
||||||
|
|
||||||
|
function Icon({width = 24, height = 24, color}) {
|
||||||
|
return <img src={`${StaticBaseUrl}/buttons/line.svg`} alt="Sign in with Line" style={{width: 24, height: 24}} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
text: "Sign in with Line",
|
||||||
|
icon: Icon,
|
||||||
|
iconFormat: name => `fa fa-${name}`,
|
||||||
|
style: {background: "#ffffff", color: "#000000"},
|
||||||
|
activeStyle: {background: "#ededee"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const LineLoginButton = createButton(config);
|
||||||
|
|
||||||
|
export default LineLoginButton;
|
@ -61,7 +61,8 @@ class LoginPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
componentDidMount() {
|
||||||
|
if (this.getApplicationObj() === null) {
|
||||||
if (this.state.type === "login" || this.state.type === "cas") {
|
if (this.state.type === "login" || this.state.type === "cas") {
|
||||||
this.getApplication();
|
this.getApplication();
|
||||||
} else if (this.state.type === "code") {
|
} else if (this.state.type === "code") {
|
||||||
@ -73,7 +74,6 @@ class LoginPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
Setting.Countries.forEach((country) => {
|
Setting.Countries.forEach((country) => {
|
||||||
new Image().src = `${Setting.StaticBaseUrl}/flag-icons/${country.country}.svg`;
|
new Image().src = `${Setting.StaticBaseUrl}/flag-icons/${country.country}.svg`;
|
||||||
});
|
});
|
||||||
@ -96,11 +96,13 @@ class LoginPage extends React.Component {
|
|||||||
AuthBackend.getApplicationLogin(oAuthParams)
|
AuthBackend.getApplicationLogin(oAuthParams)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
|
this.onUpdateApplication(res.data);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: res.data,
|
application: res.data,
|
||||||
});
|
});
|
||||||
} 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,
|
||||||
@ -117,6 +119,7 @@ class LoginPage extends React.Component {
|
|||||||
if (this.state.owner === null || this.state.owner === undefined || this.state.owner === "") {
|
if (this.state.owner === null || this.state.owner === undefined || this.state.owner === "") {
|
||||||
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
||||||
.then((application) => {
|
.then((application) => {
|
||||||
|
this.onUpdateApplication(application);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
@ -125,11 +128,13 @@ class LoginPage extends React.Component {
|
|||||||
OrganizationBackend.getDefaultApplication("admin", this.state.owner)
|
OrganizationBackend.getDefaultApplication("admin", this.state.owner)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
|
this.onUpdateApplication(res.data);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: res.data,
|
application: res.data,
|
||||||
applicationName: res.data.name,
|
applicationName: res.data.name,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
this.onUpdateApplication(null);
|
||||||
Setting.showMessage("error", res.msg);
|
Setting.showMessage("error", res.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -142,25 +147,25 @@ class LoginPage extends React.Component {
|
|||||||
}
|
}
|
||||||
ApplicationBackend.getApplication(this.state.owner, this.state.applicationName)
|
ApplicationBackend.getApplication(this.state.owner, this.state.applicationName)
|
||||||
.then((application) => {
|
.then((application) => {
|
||||||
|
this.onUpdateApplication(application);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationObj() {
|
getApplicationObj() {
|
||||||
if (this.props.application !== undefined) {
|
return this.props.application ?? this.state.application;
|
||||||
return this.props.application;
|
|
||||||
} else {
|
|
||||||
return this.state.application;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateAccount(account) {
|
onUpdateAccount(account) {
|
||||||
this.props.onUpdateAccount(account);
|
this.props.onUpdateAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateApplication(application) {
|
||||||
|
this.props.onUpdateApplication(application);
|
||||||
|
}
|
||||||
|
|
||||||
parseOffset(offset) {
|
parseOffset(offset) {
|
||||||
if (offset === 2 || offset === 4 || Setting.inIframe() || Setting.isMobile()) {
|
if (offset === 2 || offset === 4 || Setting.inIframe() || Setting.isMobile()) {
|
||||||
return "0 auto";
|
return "0 auto";
|
||||||
@ -191,8 +196,8 @@ class LoginPage extends React.Component {
|
|||||||
values["relayState"] = oAuthParams.relayState;
|
values["relayState"] = oAuthParams.relayState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.application.organization !== null && this.state.application.organization !== undefined) {
|
if (this.getApplicationObj()?.organization) {
|
||||||
values["organization"] = this.state.application.organization;
|
values["organization"] = this.getApplicationObj().organization;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
postCodeLoginAction(res) {
|
postCodeLoginAction(res) {
|
||||||
@ -573,12 +578,12 @@ class LoginPage extends React.Component {
|
|||||||
<span style={{float: "right"}}>
|
<span style={{float: "right"}}>
|
||||||
{
|
{
|
||||||
!application.enableSignUp ? null : (
|
!application.enableSignUp ? null : (
|
||||||
<>
|
<React.Fragment>
|
||||||
{i18next.t("login:No account?")}
|
{i18next.t("login:No account?")}
|
||||||
{
|
{
|
||||||
Setting.renderSignupLink(application, i18next.t("login:sign up now"))
|
Setting.renderSignupLink(application, i18next.t("login:sign up now"))
|
||||||
}
|
}
|
||||||
</>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -788,16 +793,16 @@ class LoginPage extends React.Component {
|
|||||||
if (this.props.application === undefined && !application.enablePassword && visibleOAuthProviderItems.length === 1) {
|
if (this.props.application === undefined && !application.enablePassword && visibleOAuthProviderItems.length === 1) {
|
||||||
Setting.goToLink(Provider.getAuthUrl(application, visibleOAuthProviderItems[0].provider, "signup"));
|
Setting.goToLink(Provider.getAuthUrl(application, visibleOAuthProviderItems[0].provider, "signup"));
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign: "center"}}>
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="loginBackground" style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${application.formBackgroundUrl})`}}>
|
<React.Fragment>
|
||||||
<CustomGithubCorner />
|
<CustomGithubCorner />
|
||||||
<div className="login-content" style={{margin: this.parseOffset(application.formOffset)}}>
|
<div className="login-content" style={{margin: this.props.preview ?? this.parseOffset(application.formOffset)}}>
|
||||||
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
|
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
|
||||||
<div className="login-panel">
|
<div className="login-panel">
|
||||||
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
|
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
|
||||||
@ -827,7 +832,7 @@ class LoginPage extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Col, Result, Row} from "antd";
|
import {Button, Card, Col, Result, Row} from "antd";
|
||||||
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||||
import * as UserBackend from "../backend/UserBackend";
|
import * as UserBackend from "../backend/UserBackend";
|
||||||
import * as AuthBackend from "./AuthBackend";
|
import * as AuthBackend from "./AuthBackend";
|
||||||
@ -30,7 +30,7 @@ class PromptPage extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
type: props.type,
|
type: props.type,
|
||||||
applicationName: props.applicationName !== undefined ? props.applicationName : (props.match === undefined ? null : props.match.params.applicationName),
|
applicationName: props.applicationName ?? (props.match === undefined ? null : props.match.params.applicationName),
|
||||||
application: null,
|
application: null,
|
||||||
user: null,
|
user: null,
|
||||||
};
|
};
|
||||||
@ -38,8 +38,10 @@ class PromptPage extends React.Component {
|
|||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.getUser();
|
this.getUser();
|
||||||
|
if (this.getApplicationObj() === null) {
|
||||||
this.getApplication();
|
this.getApplication();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getUser() {
|
getUser() {
|
||||||
const organizationName = this.props.account.owner;
|
const organizationName = this.props.account.owner;
|
||||||
@ -59,6 +61,7 @@ class PromptPage extends React.Component {
|
|||||||
|
|
||||||
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
||||||
.then((application) => {
|
.then((application) => {
|
||||||
|
this.onUpdateApplication(application);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
@ -66,11 +69,11 @@ class PromptPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getApplicationObj() {
|
getApplicationObj() {
|
||||||
if (this.props.application !== undefined) {
|
return this.props.application ?? this.state.application;
|
||||||
return this.props.application;
|
|
||||||
} else {
|
|
||||||
return this.state.application;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateApplication(application) {
|
||||||
|
this.props.onUpdateApplication(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseUserField(key, value) {
|
parseUserField(key, value) {
|
||||||
@ -122,7 +125,7 @@ class PromptPage extends React.Component {
|
|||||||
|
|
||||||
renderContent(application) {
|
renderContent(application) {
|
||||||
return (
|
return (
|
||||||
<div style={{width: "400px"}}>
|
<div style={{width: "500px"}}>
|
||||||
{
|
{
|
||||||
this.renderAffiliation(application)
|
this.renderAffiliation(application)
|
||||||
}
|
}
|
||||||
@ -247,9 +250,9 @@ class PromptPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<div style={{display: "flex", flex: "1", justifyContent: "center"}}>
|
||||||
<Col span={24} style={{display: "flex", justifyContent: "center"}}>
|
<Card>
|
||||||
<div style={{marginTop: "80px", marginBottom: "50px", textAlign: "center"}}>
|
<div style={{marginTop: "30px", marginBottom: "30px", textAlign: "center"}}>
|
||||||
{
|
{
|
||||||
Setting.renderHelmet(application)
|
Setting.renderHelmet(application)
|
||||||
}
|
}
|
||||||
@ -259,16 +262,12 @@ class PromptPage extends React.Component {
|
|||||||
{
|
{
|
||||||
this.renderContent(application)
|
this.renderContent(application)
|
||||||
}
|
}
|
||||||
<Row style={{margin: 10}}>
|
|
||||||
<Col span={18}>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<div style={{marginTop: "50px"}}>
|
<div style={{marginTop: "50px"}}>
|
||||||
<Button disabled={!Setting.isPromptAnswered(this.state.user, application)} type="primary" size="large" onClick={() => {this.submitUserEdit(true);}}>{i18next.t("code:Submit and complete")}</Button>
|
<Button disabled={!Setting.isPromptAnswered(this.state.user, application)} type="primary" size="large" onClick={() => {this.submitUserEdit(true);}}>{i18next.t("code:Submit and complete")}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Card>
|
||||||
</Row>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,10 @@ const authInfo = {
|
|||||||
Bilibili: {
|
Bilibili: {
|
||||||
endpoint: "https://passport.bilibili.com/register/pc_oauth2.html",
|
endpoint: "https://passport.bilibili.com/register/pc_oauth2.html",
|
||||||
},
|
},
|
||||||
|
Line: {
|
||||||
|
scope: "profile%20openid%20email",
|
||||||
|
endpoint: "https://access.line.me/oauth2/v2.1/authorize",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getProviderUrl(provider) {
|
export function getProviderUrl(provider) {
|
||||||
@ -256,5 +260,7 @@ export function getAuthUrl(application, provider, method) {
|
|||||||
return `${provider.customAuthUrl}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${provider.customScope}&response_type=code&state=${state}`;
|
return `${provider.customAuthUrl}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${provider.customScope}&response_type=code&state=${state}`;
|
||||||
} else if (provider.type === "Bilibili") {
|
} else if (provider.type === "Bilibili") {
|
||||||
return `${endpoint}#/?client_id=${provider.clientId}&return_url=${redirectUri}&state=${state}&response_type=code`;
|
return `${endpoint}#/?client_id=${provider.clientId}&return_url=${redirectUri}&state=${state}&response_type=code`;
|
||||||
|
} else if (provider.type === "Line") {
|
||||||
|
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import SteamLoginButton from "./SteamLoginButton";
|
|||||||
import BilibiliLoginButton from "./BilibiliLoginButton";
|
import BilibiliLoginButton from "./BilibiliLoginButton";
|
||||||
import OktaLoginButton from "./OktaLoginButton";
|
import OktaLoginButton from "./OktaLoginButton";
|
||||||
import DouyinLoginButton from "./DouyinLoginButton";
|
import DouyinLoginButton from "./DouyinLoginButton";
|
||||||
|
import LineLoginButton from "./LineLoginButton";
|
||||||
import * as AuthBackend from "./AuthBackend";
|
import * as AuthBackend from "./AuthBackend";
|
||||||
import {getEvent} from "./Util";
|
import {getEvent} from "./Util";
|
||||||
import {Modal} from "antd";
|
import {Modal} from "antd";
|
||||||
@ -93,6 +94,8 @@ function getSigninButton(type) {
|
|||||||
return <OktaLoginButton text={text} align={"center"} />;
|
return <OktaLoginButton text={text} align={"center"} />;
|
||||||
} else if (type === "Douyin") {
|
} else if (type === "Douyin") {
|
||||||
return <DouyinLoginButton text={text} align={"center"} />;
|
return <DouyinLoginButton text={text} align={"center"} />;
|
||||||
|
} else if (type === "Line") {
|
||||||
|
return <LineLoginButton text={text} align={"center"} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
|
@ -95,7 +95,7 @@ class SamlCallback extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign: "center"}}>
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
{
|
{
|
||||||
(this.state.msg === null) ? (
|
(this.state.msg === null) ? (
|
||||||
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
<Spin size="large" tip={i18next.t("login:Signing in...")} style={{paddingTop: "10%"}} />
|
||||||
|
@ -22,7 +22,6 @@ class SelfForgetPage extends React.Component {
|
|||||||
<ForgetPage
|
<ForgetPage
|
||||||
type={"forgotPassword"}
|
type={"forgotPassword"}
|
||||||
applicationName={authConfig.appName}
|
applicationName={authConfig.appName}
|
||||||
account={this.props.account}
|
|
||||||
{...this.props}
|
{...this.props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,7 @@ import {authConfig} from "./Auth";
|
|||||||
class SelfLoginPage extends React.Component {
|
class SelfLoginPage extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<LoginPage type={"login"} mode={"signin"} applicationName={authConfig.appName} account={this.props.account} {...this.props} />
|
<LoginPage type={"login"} mode={"signin"} applicationName={authConfig.appName} {...this.props} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ class SignupPage extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
applicationName: props.match?.params.applicationName !== undefined ? props.match.params.applicationName : authConfig.appName,
|
applicationName: props.match.params?.applicationName ?? authConfig.appName,
|
||||||
application: null,
|
application: null,
|
||||||
email: "",
|
email: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
@ -91,12 +91,14 @@ class SignupPage extends React.Component {
|
|||||||
sessionStorage.setItem("signinUrl", signinUrl);
|
sessionStorage.setItem("signinUrl", signinUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.getApplicationObj() === null) {
|
||||||
if (applicationName !== undefined) {
|
if (applicationName !== undefined) {
|
||||||
this.getApplication(applicationName);
|
this.getApplication(applicationName);
|
||||||
} else {
|
} else {
|
||||||
Setting.showMessage("error", `Unknown application name: ${applicationName}`);
|
Setting.showMessage("error", `Unknown application name: ${applicationName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getApplication(applicationName) {
|
getApplication(applicationName) {
|
||||||
if (applicationName === undefined) {
|
if (applicationName === undefined) {
|
||||||
@ -105,6 +107,7 @@ class SignupPage extends React.Component {
|
|||||||
|
|
||||||
ApplicationBackend.getApplication("admin", applicationName)
|
ApplicationBackend.getApplication("admin", applicationName)
|
||||||
.then((application) => {
|
.then((application) => {
|
||||||
|
this.onUpdateApplication(application);
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
@ -128,11 +131,7 @@ class SignupPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getApplicationObj() {
|
getApplicationObj() {
|
||||||
if (this.props.application !== undefined) {
|
return this.props.application ?? this.state.application;
|
||||||
return this.props.application;
|
|
||||||
} else {
|
|
||||||
return this.state.application;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTermsofuseContent(url) {
|
getTermsofuseContent(url) {
|
||||||
@ -149,6 +148,10 @@ class SignupPage extends React.Component {
|
|||||||
this.props.onUpdateAccount(account);
|
this.props.onUpdateAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateApplication(application) {
|
||||||
|
this.props.onUpdateApplication(application);
|
||||||
|
}
|
||||||
|
|
||||||
parseOffset(offset) {
|
parseOffset(offset) {
|
||||||
if (offset === 2 || offset === 4 || Setting.inIframe() || Setting.isMobile()) {
|
if (offset === 2 || offset === 4 || Setting.inIframe() || Setting.isMobile()) {
|
||||||
return "0 auto";
|
return "0 auto";
|
||||||
@ -632,9 +635,9 @@ class SignupPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="loginBackground" style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${application.formBackgroundUrl})`}}>
|
<React.Fragment>
|
||||||
<CustomGithubCorner />
|
<CustomGithubCorner />
|
||||||
<div className="login-content" style={{margin: this.parseOffset(application.formOffset)}}>
|
<div className="login-content" style={{margin: this.props.preview ?? this.parseOffset(application.formOffset)}}>
|
||||||
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
|
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
|
||||||
<div className="login-panel" >
|
<div className="login-panel" >
|
||||||
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
|
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
|
||||||
@ -657,7 +660,7 @@ class SignupPage extends React.Component {
|
|||||||
{
|
{
|
||||||
this.renderModal()
|
this.renderModal()
|
||||||
}
|
}
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class OAuthWidget extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={24 - this.props.labelSpan} >
|
<Col span={24 - this.props.labelSpan} >
|
||||||
<img style={{marginRight: "10px"}} width={30} height={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
|
<img style={{marginRight: "10px"}} width={30} height={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
|
||||||
<span style={{width: this.props.labelSpan === 3 ? "300px" : "130px", display: (Setting.isMobile()) ? "inline" : "inline-block"}}>
|
<span style={{width: this.props.labelSpan === 3 ? "300px" : "200px", display: (Setting.isMobile()) ? "inline" : "inline-block"}}>
|
||||||
{
|
{
|
||||||
linkedValue === "" ? (
|
linkedValue === "" ? (
|
||||||
"(empty)"
|
"(empty)"
|
||||||
|
@ -293,14 +293,15 @@ class PolicyTable extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (<>
|
return (
|
||||||
|
<React.Fragment>
|
||||||
<Button type="primary" disabled={this.state.editingIndex !== ""} onClick={() => {this.synPolicies();}}>
|
<Button type="primary" disabled={this.state.editingIndex !== ""} onClick={() => {this.synPolicies();}}>
|
||||||
{i18next.t("adapter:Sync")}
|
{i18next.t("adapter:Sync")}
|
||||||
</Button>
|
</Button>
|
||||||
{
|
{
|
||||||
this.renderTable(this.state.policyLists)
|
this.renderTable(this.state.policyLists)
|
||||||
}
|
}
|
||||||
</>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
export const RedirectForm = (props) => {
|
export const RedirectForm = (props) => {
|
||||||
|
|
||||||
@ -20,8 +21,9 @@ export const RedirectForm = (props) => {
|
|||||||
document.getElementById("saml").submit();
|
document.getElementById("saml").submit();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
<p>Redirecting, please wait.</p>
|
<React.Fragment>
|
||||||
|
<p>{i18next.t("login:Redirecting, please wait.")}</p>
|
||||||
<form id="saml" method="post" action={props.redirectUrl}>
|
<form id="saml" method="post" action={props.redirectUrl}>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
@ -36,7 +38,7 @@ export const RedirectForm = (props) => {
|
|||||||
value={props.relayState}
|
value={props.relayState}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "Weiter mit",
|
"Continue with": "Weiter mit",
|
||||||
"Email or phone": "E-Mail oder Telefon",
|
"Email or phone": "E-Mail oder Telefon",
|
||||||
"Forgot password?": "Passwort vergessen?",
|
"Forgot password?": "Passwort vergessen?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Logging out...",
|
"Logging out...": "Logging out...",
|
||||||
"No account?": "Kein Konto?",
|
"No account?": "Kein Konto?",
|
||||||
"Or sign in with another account": "Oder melden Sie sich mit einem anderen Konto an",
|
"Or sign in with another account": "Oder melden Sie sich mit einem anderen Konto an",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "Bitte geben Sie Ihr Passwort ein!",
|
"Please input your password!": "Bitte geben Sie Ihr Passwort ein!",
|
||||||
"Please input your password, at least 6 characters!": "Bitte geben Sie Ihr Passwort ein, mindestens 6 Zeichen!",
|
"Please input your password, at least 6 characters!": "Bitte geben Sie Ihr Passwort ein, mindestens 6 Zeichen!",
|
||||||
"Please input your username, Email or phone!": "Bitte geben Sie Ihren Benutzernamen, E-Mail oder Telefon ein!",
|
"Please input your username, Email or phone!": "Bitte geben Sie Ihren Benutzernamen, E-Mail oder Telefon ein!",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "Anmelden",
|
"Sign In": "Anmelden",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "Mit {type} anmelden",
|
"Sign in with {type}": "Mit {type} anmelden",
|
||||||
@ -721,6 +726,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",
|
||||||
@ -736,6 +742,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...",
|
||||||
@ -751,6 +758,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",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "Continue with",
|
"Continue with": "Continue with",
|
||||||
"Email or phone": "Email or phone",
|
"Email or phone": "Email or phone",
|
||||||
"Forgot password?": "Forgot password?",
|
"Forgot password?": "Forgot password?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Logging out...",
|
"Logging out...": "Logging out...",
|
||||||
"No account?": "No account?",
|
"No account?": "No account?",
|
||||||
"Or sign in with another account": "Or sign in with another account",
|
"Or sign in with another account": "Or sign in with another account",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "Sign in with {type}",
|
"Sign in with {type}": "Sign in with {type}",
|
||||||
@ -721,6 +726,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",
|
||||||
@ -736,6 +742,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...",
|
||||||
@ -751,6 +758,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",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "Continuer avec",
|
"Continue with": "Continuer avec",
|
||||||
"Email or phone": "Courriel ou téléphone",
|
"Email or phone": "Courriel ou téléphone",
|
||||||
"Forgot password?": "Mot de passe oublié ?",
|
"Forgot password?": "Mot de passe oublié ?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Logging out...",
|
"Logging out...": "Logging out...",
|
||||||
"No account?": "Pas de compte ?",
|
"No account?": "Pas de compte ?",
|
||||||
"Or sign in with another account": "Ou connectez-vous avec un autre compte",
|
"Or sign in with another account": "Ou connectez-vous avec un autre compte",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "Veuillez saisir votre mot de passe !",
|
"Please input your password!": "Veuillez saisir votre mot de passe !",
|
||||||
"Please input your password, at least 6 characters!": "Veuillez entrer votre mot de passe, au moins 6 caractères !",
|
"Please input your password, at least 6 characters!": "Veuillez entrer votre mot de passe, au moins 6 caractères !",
|
||||||
"Please input your username, Email or phone!": "Veuillez entrer votre nom d'utilisateur, votre e-mail ou votre téléphone!",
|
"Please input your username, Email or phone!": "Veuillez entrer votre nom d'utilisateur, votre e-mail ou votre téléphone!",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "Se connecter",
|
"Sign In": "Se connecter",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "Se connecter avec {type}",
|
"Sign in with {type}": "Se connecter avec {type}",
|
||||||
@ -721,6 +726,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",
|
||||||
@ -736,6 +742,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...",
|
||||||
@ -751,6 +758,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": "デフォルトのアバター",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "次で続ける",
|
"Continue with": "次で続ける",
|
||||||
"Email or phone": "Eメールまたは電話番号",
|
"Email or phone": "Eメールまたは電話番号",
|
||||||
"Forgot password?": "パスワードを忘れましたか?",
|
"Forgot password?": "パスワードを忘れましたか?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Logging out...",
|
"Logging out...": "Logging out...",
|
||||||
"No account?": "アカウントがありませんか?",
|
"No account?": "アカウントがありませんか?",
|
||||||
"Or sign in with another account": "または別のアカウントでサインイン",
|
"Or sign in with another account": "または別のアカウントでサインイン",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "パスワードを入力してください!",
|
"Please input your password!": "パスワードを入力してください!",
|
||||||
"Please input your password, at least 6 characters!": "6文字以上でパスワードを入力してください!",
|
"Please input your password, at least 6 characters!": "6文字以上でパスワードを入力してください!",
|
||||||
"Please input your username, Email or phone!": "ユーザー名、メールアドレスまたは電話番号を入力してください。",
|
"Please input your username, Email or phone!": "ユーザー名、メールアドレスまたは電話番号を入力してください。",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "サインイン",
|
"Sign In": "サインイン",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "{type} でサインイン",
|
"Sign in with {type}": "{type} でサインイン",
|
||||||
@ -721,6 +726,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": "場所 → ツールチップ",
|
||||||
@ -736,6 +742,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...": "電話番号をリセット...",
|
||||||
@ -751,6 +758,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",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "Continue with",
|
"Continue with": "Continue with",
|
||||||
"Email or phone": "Email or phone",
|
"Email or phone": "Email or phone",
|
||||||
"Forgot password?": "Forgot password?",
|
"Forgot password?": "Forgot password?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Logging out...",
|
"Logging out...": "Logging out...",
|
||||||
"No account?": "No account?",
|
"No account?": "No account?",
|
||||||
"Or sign in with another account": "Or sign in with another account",
|
"Or sign in with another account": "Or sign in with another account",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "Sign in with {type}",
|
"Sign in with {type}": "Sign in with {type}",
|
||||||
@ -721,6 +726,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",
|
||||||
@ -736,6 +742,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...",
|
||||||
@ -751,6 +758,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": "Аватар по умолчанию",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "Продолжить с",
|
"Continue with": "Продолжить с",
|
||||||
"Email or phone": "Электронная почта или телефон",
|
"Email or phone": "Электронная почта или телефон",
|
||||||
"Forgot password?": "Забыли пароль?",
|
"Forgot password?": "Забыли пароль?",
|
||||||
|
"Loading": "Loading",
|
||||||
"Logging out...": "Выход...",
|
"Logging out...": "Выход...",
|
||||||
"No account?": "Нет учетной записи?",
|
"No account?": "Нет учетной записи?",
|
||||||
"Or sign in with another account": "Или войти с помощью другой учетной записи",
|
"Or sign in with another account": "Или войти с помощью другой учетной записи",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "Пожалуйста, введите ваш пароль!",
|
"Please input your password!": "Пожалуйста, введите ваш пароль!",
|
||||||
"Please input your password, at least 6 characters!": "Пожалуйста, введите ваш пароль, по крайней мере 6 символов!",
|
"Please input your password, at least 6 characters!": "Пожалуйста, введите ваш пароль, по крайней мере 6 символов!",
|
||||||
"Please input your username, Email or phone!": "Пожалуйста, введите ваше имя пользователя, адрес электронной почты или телефон!",
|
"Please input your username, Email or phone!": "Пожалуйста, введите ваше имя пользователя, адрес электронной почты или телефон!",
|
||||||
|
"Redirecting, please wait.": "Redirecting, please wait.",
|
||||||
"Sign In": "Войти",
|
"Sign In": "Войти",
|
||||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||||
"Sign in with {type}": "Войти с помощью {type}",
|
"Sign in with {type}": "Войти с помощью {type}",
|
||||||
@ -721,6 +726,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": "Расположение - Подсказка",
|
||||||
@ -736,6 +742,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...": "Сбросить телефон...",
|
||||||
@ -751,6 +758,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": "默认头像",
|
||||||
@ -299,6 +302,7 @@
|
|||||||
"Continue with": "使用以下账号继续",
|
"Continue with": "使用以下账号继续",
|
||||||
"Email or phone": "Email或手机号",
|
"Email or phone": "Email或手机号",
|
||||||
"Forgot password?": "忘记密码?",
|
"Forgot password?": "忘记密码?",
|
||||||
|
"Loading": "加载中",
|
||||||
"Logging out...": "正在退出登录...",
|
"Logging out...": "正在退出登录...",
|
||||||
"No account?": "没有账号?",
|
"No account?": "没有账号?",
|
||||||
"Or sign in with another account": "或者,登录其他账号",
|
"Or sign in with another account": "或者,登录其他账号",
|
||||||
@ -308,6 +312,7 @@
|
|||||||
"Please input your password!": "请输入您的密码!",
|
"Please input your password!": "请输入您的密码!",
|
||||||
"Please input your password, at least 6 characters!": "请输入您的密码,不少于6位",
|
"Please input your password, at least 6 characters!": "请输入您的密码,不少于6位",
|
||||||
"Please input your username, Email or phone!": "请输入您的用户名、Email或手机号!",
|
"Please input your username, Email or phone!": "请输入您的用户名、Email或手机号!",
|
||||||
|
"Redirecting, please wait.": "正在跳转, 请稍等.",
|
||||||
"Sign In": "登录",
|
"Sign In": "登录",
|
||||||
"Sign in with WebAuthn": "WebAuthn登录",
|
"Sign in with WebAuthn": "WebAuthn登录",
|
||||||
"Sign in with {type}": "{type}登录",
|
"Sign in with {type}": "{type}登录",
|
||||||
@ -721,6 +726,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": "居住地址所在的城市",
|
||||||
@ -736,6 +742,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...": "重置手机号...",
|
||||||
@ -751,6 +758,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;
|
Reference in New Issue
Block a user