Compare commits

..

24 Commits

Author SHA1 Message Date
Yang Luo
cba338eef2 Merge pull request #973 from qianxi0410/eslint
feat(web): add some eslint rules
2022-08-07 00:41:51 +08:00
qianxi0410
c428de6e42 feat: fix some comma dangle 2022-08-07 00:17:27 +08:00
qianxi0410
9bca6bb72e feat: no-multi-spacing 2022-08-07 00:06:20 +08:00
qianxi0410
cd966116d4 feat: comma dangle 2022-08-06 23:54:56 +08:00
qianxi0410
9abf1b9d73 feat: key spacing 2022-08-06 23:47:28 +08:00
qianxi0410
6aaba6debd feat: space between infix op 2022-08-06 23:43:09 +08:00
qianxi0410
77565712e0 feat: no-multi-empty-lines 2022-08-06 23:38:03 +08:00
qianxi0410
d025259db7 feat: indent 2022-08-06 23:36:20 +08:00
Artem
aafdc546fa fix: panic when creating a user in a non-existent org (#969) 2022-08-06 22:30:56 +08:00
q1anx1
539ca2d731 chore(web): add fix command (#964) 2022-08-05 23:40:04 +08:00
Ryao
ea326b3513 fix: show social buttons on signup page (#962) 2022-08-05 18:59:56 +08:00
Товарищ программист
98ef766fb4 fix: fix webauthn entry cannot add bug (#960)
* fix: fix webauthn

* Update LoginPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-05 17:43:04 +08:00
Gucheng Wang
e94ada9ea2 Fix new accountItem. 2022-08-05 15:36:07 +08:00
Resulte Lee
4ea482223d feat: add geetest captcha (#953) 2022-08-04 20:55:04 +08:00
Gucheng Wang
d55ae7d1d2 Enable some other DBs 2022-08-04 20:28:09 +08:00
imp2002
d72e00605f fix: updateProviderField when add provider payment (#952) 2022-08-04 19:39:25 +08:00
zzjin
be74cb621f feat: Support sub-directory (#943)
By adding PUBLIC_URL to relative `.`

Signed-off-by: zzjin <tczzjin@gmail.com>
2022-08-02 00:21:15 +08:00
q1anx1
13404d6035 feat: fix binding after registration causes the page to crash (#945) 2022-08-01 21:08:10 +08:00
Mikey
afa9c530ad fix: panic triggered when user is nil (#940) 2022-07-31 23:23:36 +08:00
Yang Luo
1600615aca Support sqlite3 DB 2022-07-31 18:11:18 +08:00
Mikey
2bb8491499 fix: unable to get user if profile is private (#936) 2022-07-31 10:54:41 +08:00
Mikey
293283ed25 feat: add get user by phone (#934)
* fix: check reset phone & email modify rules

* Update verification.go

* Update organization.go

* feat: add get user by phone

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-31 01:02:28 +08:00
q1anx1
9cb519d1e9 fix: Admins should not be allowed to add third-party login for their members (#932)
* feat: admin can unlink the other user

* feat: global admin can unlink other user

* fix
2022-07-30 23:11:02 +08:00
Yixiang Zhao
fb9b8f1662 fix: skip the duplicated users when sync users (#928)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-30 22:24:23 +08:00
90 changed files with 782 additions and 493 deletions

82
captcha/geetest.go Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package captcha
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
"github.com/casdoor/casdoor/util"
)
const GEETESTCaptchaVerifyUrl = "http://gcaptcha4.geetest.com/validate"
type GEETESTCaptchaProvider struct {
}
func NewGEETESTCaptchaProvider() *GEETESTCaptchaProvider {
captcha := &GEETESTCaptchaProvider{}
return captcha
}
func (captcha *GEETESTCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
pathData, err := url.ParseQuery(token)
if err != nil {
return false, err
}
signToken := util.GetHmacSha256(clientSecret, pathData["lot_number"][0])
formData := make(url.Values)
formData["lot_number"] = []string{pathData["lot_number"][0]}
formData["captcha_output"] = []string{pathData["captcha_output"][0]}
formData["pass_token"] = []string{pathData["pass_token"][0]}
formData["gen_time"] = []string{pathData["gen_time"][0]}
formData["sign_token"] = []string{signToken}
captchaId := pathData["captcha_id"][0]
cli := http.Client{Timeout: time.Second * 5}
resp, err := cli.PostForm(fmt.Sprintf("%s?captcha_id=%s", GEETESTCaptchaVerifyUrl, captchaId), formData)
if err != nil || resp.StatusCode != 200 {
return false, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err
}
type captchaResponse struct {
Result string `json:"result"`
Reason string `json:"reason"`
}
captchaResp := &captchaResponse{}
err = json.Unmarshal(body, captchaResp)
if err != nil {
return false, err
}
if captchaResp.Result == "success" {
return true, nil
}
return false, errors.New(captchaResp.Reason)
}

View File

@@ -27,6 +27,8 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return NewHCaptchaProvider()
} else if captchaType == "Aliyun Captcha" {
return NewAliyunCaptchaProvider()
} else if captchaType == "GEETEST" {
return NewGEETESTCaptchaProvider()
}
return nil
}

View File

@@ -21,7 +21,8 @@ import (
)
type LinkForm struct {
ProviderType string `json:"providerType"`
ProviderType string `json:"providerType"`
User object.User `json:"user"`
}
// Unlink ...
@@ -40,16 +41,55 @@ func (c *ApiController) Unlink() {
}
providerType := form.ProviderType
// the user will be unlinked from the provider
unlinkedUser := form.User
user := object.GetUser(userId)
value := object.GetUserField(user, providerType)
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
c.ResponseError("You are not the global admin, you can't unlink other users")
return
}
if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin {
// if the user is unlinking themselves, should check the provider can be unlinked, if not, we should return an error.
application := object.GetApplicationByUser(user)
if application == nil {
c.ResponseError("You can't unlink yourself, you are not a member of any application")
return
}
if len(application.Providers) == 0 {
c.ResponseError("This application has no providers")
return
}
provider := application.GetProviderItemByType(providerType)
if provider == nil {
c.ResponseError("This application has no providers of type " + providerType)
return
}
if !provider.CanUnlink {
c.ResponseError("This provider can't be unlinked")
return
}
}
// only two situations can happen here
// 1. the user is the global admin
// 2. the user is unlinking themselves and provider can be unlinked
value := object.GetUserField(&unlinkedUser, providerType)
if value == "" {
c.ResponseError("Please link first", value)
return
}
object.ClearUserOAuthProperties(user, providerType)
object.ClearUserOAuthProperties(&unlinkedUser, providerType)
object.LinkUserAccount(user, providerType, "")
object.LinkUserAccount(&unlinkedUser, providerType, "")
c.ResponseOk()
}

View File

@@ -80,12 +80,16 @@ func (c *ApiController) GetUsers() {
// @Title GetUser
// @Tag User API
// @Description get user
// @Param id query string true "The id of the user"
// @Param id query string true "The id of the user"
// @Param owner query string false "The owner of the user"
// @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user"
// @Success 200 {object} object.User The Response object
// @router /get-user [get]
func (c *ApiController) GetUser() {
id := c.Input().Get("id")
email := c.Input().Get("email")
phone := c.Input().Get("phone")
userId := c.Input().Get("userId")
owner := c.Input().Get("owner")
@@ -96,7 +100,7 @@ func (c *ApiController) GetUser() {
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", owner))
if !organization.IsProfilePublic {
requestUserId := c.GetSessionUsername()
hasPermission, err := object.CheckUserPermission(requestUserId, id, false)
hasPermission, err := object.CheckUserPermission(requestUserId, id, owner, false)
if !hasPermission {
c.ResponseError(err.Error())
return
@@ -104,18 +108,23 @@ func (c *ApiController) GetUser() {
}
var user *object.User
if email != "" {
switch {
case email != "":
user = object.GetUserByEmail(owner, email)
} else if userId != "" {
case phone != "":
user = object.GetUserByPhone(owner, phone)
case userId != "":
user = object.GetUserByUserId(owner, userId)
} else {
default:
user = object.GetUser(id)
}
roles := object.GetRolesByUser(user.GetId())
user.Roles = roles
permissions := object.GetPermissionsByUser(user.GetId())
user.Permissions = permissions
if user != nil {
roles := object.GetRolesByUser(user.GetId())
user.Roles = roles
permissions := object.GetPermissionsByUser(user.GetId())
user.Permissions = permissions
}
c.Data["json"] = object.GetMaskedUser(user)
c.ServeJSON()
@@ -257,7 +266,7 @@ func (c *ApiController) SetPassword() {
requestUserId := c.GetSessionUsername()
userId := fmt.Sprintf("%s/%s", userOwner, userName)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, true)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true)
if !hasPermission {
c.ResponseError(err.Error())
return

2
go.mod
View File

@@ -14,6 +14,7 @@ require (
github.com/casdoor/goth v1.69.0-FIX2
github.com/casdoor/oss v1.2.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0
@@ -23,6 +24,7 @@ require (
github.com/google/uuid v1.2.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v0.9.0
github.com/lib/pq v1.8.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1

2
go.sum
View File

@@ -125,6 +125,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
@@ -173,6 +174,7 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=

View File

@@ -21,9 +21,10 @@ import (
"github.com/astaxie/beego"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
//_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
//_ "github.com/lib/pq" // db = postgres
_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
"xorm.io/core"
"xorm.io/xorm"
)

View File

@@ -197,14 +197,18 @@ func filterField(field string) bool {
return reFieldWhiteList.MatchString(field)
}
func CheckUserPermission(requestUserId, userId string, strict bool) (bool, error) {
func CheckUserPermission(requestUserId, userId, userOwner string, strict bool) (bool, error) {
if requestUserId == "" {
return false, fmt.Errorf("please login first")
}
targetUser := GetUser(userId)
if targetUser == nil {
return false, fmt.Errorf("the user: %s doesn't exist", userId)
if userId != "" {
targetUser := GetUser(userId)
if targetUser == nil {
return false, fmt.Errorf("the user: %s doesn't exist", userId)
}
userOwner = targetUser.Owner
}
hasPermission := false
@@ -219,7 +223,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool) (bool, error
hasPermission = true
} else if requestUserId == userId {
hasPermission = true
} else if targetUser.Owner == requestUser.Owner {
} else if userOwner == requestUser.Owner {
if strict {
hasPermission = requestUser.IsAdmin
} else {

View File

@@ -33,6 +33,15 @@ func (application *Application) GetProviderItem(providerName string) *ProviderIt
return nil
}
func (application *Application) GetProviderItemByType(providerType string) *ProviderItem {
for _, item := range application.Providers {
if item.Provider.Type == providerType {
return item
}
}
return nil
}
func (pi *ProviderItem) IsProviderVisible() bool {
if pi.Provider == nil {
return false

View File

@@ -22,7 +22,7 @@ import (
func (syncer *Syncer) syncUsers() {
fmt.Printf("Running syncUsers()..\n")
users, userMap := syncer.getUserMap()
users, userMap, userNameMap := syncer.getUserMap()
oUsers, oUserMap, err := syncer.getOriginalUserMap()
if err != nil {
fmt.Printf(err.Error())
@@ -44,9 +44,11 @@ func (syncer *Syncer) syncUsers() {
for _, oUser := range oUsers {
id := oUser.Id
if _, ok := userMap[id]; !ok {
newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
fmt.Printf("New user: %v\n", newUser)
newUsers = append(newUsers, newUser)
if _, ok := userNameMap[oUser.Name]; !ok {
newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
fmt.Printf("New user: %v\n", newUser)
newUsers = append(newUsers, newUser)
}
} else {
user := userMap[id]
oHash := syncer.calculateHash(oUser)

View File

@@ -19,12 +19,15 @@ func (syncer *Syncer) getUsers() []*User {
return users
}
func (syncer *Syncer) getUserMap() ([]*User, map[string]*User) {
func (syncer *Syncer) getUserMap() ([]*User, map[string]*User, map[string]*User) {
users := syncer.getUsers()
m := map[string]*User{}
m1 := map[string]*User{}
m2 := map[string]*User{}
for _, user := range users {
m[user.Id] = user
m1[user.Id] = user
m2[user.Name] = user
}
return users, m
return users, m1, m2
}

View File

@@ -73,7 +73,7 @@ type User struct {
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"`
Github string `xorm:"varchar(100)" json:"github"`
GitHub string `xorm:"github varchar(100)" json:"github"`
Google string `xorm:"varchar(100)" json:"google"`
QQ string `xorm:"qq varchar(100)" json:"qq"`
WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
@@ -273,6 +273,24 @@ func GetUserByEmail(owner string, email string) *User {
}
}
func GetUserByPhone(owner string, phone string) *User {
if owner == "" || phone == "" {
return nil
}
user := User{Owner: owner, Phone: phone}
existed, err := adapter.Engine.Get(&user)
if err != nil {
panic(err)
}
if existed {
return &user
} else {
return nil
}
}
func GetUserByUserId(owner string, userId string) *User {
if owner == "" || userId == "" {
return nil
@@ -399,6 +417,10 @@ func AddUser(user *User) bool {
}
organization := GetOrganizationByUser(user)
if organization == nil {
return false
}
user.UpdateUserPassword(organization)
user.UpdateUserHash()

View File

@@ -37,11 +37,11 @@ func TestSyncAvatarsFromGitHub(t *testing.T) {
users := GetGlobalUsers()
for _, user := range users {
if user.Github == "" {
if user.GitHub == "" {
continue
}
user.Avatar = fmt.Sprintf("https://avatars.githubusercontent.com/%s", user.Github)
user.Avatar = fmt.Sprintf("https://avatars.githubusercontent.com/%s", user.GitHub)
updateUserColumn("avatar", user)
}
}

View File

@@ -17,7 +17,9 @@ package util
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
)
func GetHmacSha1(keyStr, value string) string {
@@ -28,3 +30,10 @@ func GetHmacSha1(keyStr, value string) string {
return res
}
func GetHmacSha256(key string, data string) string {
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(data))
return hex.EncodeToString(mac.Sum(nil))
}

1
web/.env Normal file
View File

@@ -0,0 +1 @@
PUBLIC_URL=.

View File

@@ -21,7 +21,7 @@
"rules": {
// "eqeqeq": "error",
"semi": ["error", "always"],
// "indent": ["error", 2],
"indent": ["error", 2],
// follow antd's style guide
"quotes": ["error", "double"],
"jsx-quotes": ["error", "prefer-double"],
@@ -48,6 +48,19 @@
"sort-imports": ["error", {
"ignoreDeclarationSort": true
}],
"no-multiple-empty-lines": ["error", { "max": 1, "maxBOF": 0, "maxEOF": 0 }],
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"space-infix-ops": "error",
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"comma-style": ["error", "last"],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}],
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
"react/prop-types": "off",

View File

@@ -34,7 +34,7 @@ module.exports = {
"/cas/validate": {
target: "http://localhost:8000",
changeOrigin: true,
}
},
},
},
plugins: [

View File

@@ -39,7 +39,8 @@
"test": "craco test",
"eject": "craco eject",
"crowdin:sync": "crowdin upload && crowdin download",
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\""
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
"fix": "eslint --fix ."
},
"eslintConfig": {
"extends": "react-app"

View File

@@ -38,7 +38,7 @@ class AccountTable extends React.Component {
}
addRow(table) {
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true};
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true, viewRule: "Public", modifyRule: "Self"};
if (table === undefined) {
table = [];
}
@@ -116,7 +116,7 @@ class AccountTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("provider:visible"),
@@ -129,7 +129,7 @@ class AccountTable extends React.Component {
this.updateField(table, index, "visible", checked);
}} />
);
}
},
},
{
title: i18next.t("organization:viewRule"),
@@ -156,7 +156,7 @@ class AccountTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("organization:modifyRule"),
@@ -191,7 +191,7 @@ class AccountTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -211,7 +211,7 @@ class AccountTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -238,7 +238,7 @@ class App extends Component {
const owner = this.state.account.owner;
this.setState({
account: null
account: null,
});
Setting.showMessage("success", "Logged out successfully");
@@ -258,7 +258,7 @@ class App extends Component {
onUpdateAccount(account) {
this.setState({
account: account
account: account,
});
}
@@ -566,7 +566,7 @@ class App extends Component {
renderContent() {
if (!Setting.isMobile()) {
return (
<div style={{display: "flex", flex: "auto", width:"100%", flexDirection: "column"}}>
<div style={{display: "flex", flex: "auto", width: "100%", flexDirection: "column"}}>
<Layout style={{display: "flex", alignItems: "stretch"}}>
<Header style={{padding: "0", marginBottom: "3px"}}>
{

View File

@@ -156,7 +156,7 @@ class ApplicationEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitApplicationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteApplication()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
@@ -181,7 +181,7 @@ class ApplicationEditPage extends React.Component {
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Logo"), i18next.t("general:Logo - Tooltip"))} :
</Col>
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} :{}}>
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
@@ -583,7 +583,7 @@ class ApplicationEditPage extends React.Component {
{i18next.t("application:Copy signup page URL")}
</Button>
<br />
<div style={{position: "relative", width: "90%", 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: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
{
this.state.application.enablePassword ? (
<SignupPage application={this.state.application} />
@@ -603,7 +603,7 @@ class ApplicationEditPage extends React.Component {
{i18next.t("application:Copy signin page URL")}
</Button>
<br />
<div style={{position: "relative", width: "90%", 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: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
<div style={maskStyle}></div>
</div>

View File

@@ -99,7 +99,7 @@ class ApplicationListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -109,7 +109,7 @@ class ApplicationListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -130,7 +130,7 @@ class ApplicationListPage extends BaseListPage {
<img src={text} alt={text} width={150} />
</a>
);
}
},
},
{
title: i18next.t("general:Organization"),
@@ -145,7 +145,7 @@ class ApplicationListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Providers"),
@@ -222,7 +222,7 @@ class ApplicationListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -73,7 +73,7 @@ class CertEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteCert()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :

View File

@@ -82,7 +82,7 @@ class CertListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -92,7 +92,7 @@ class CertListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -169,7 +169,7 @@ class CertListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -42,7 +42,7 @@ class LdapEditPage extends React.Component {
.then((res) => {
if (res.status === "ok") {
this.setState({
ldap: res.data
ldap: res.data,
});
} else {
Setting.showMessage("error", res.msg);
@@ -71,7 +71,7 @@ class LdapEditPage extends React.Component {
return (
<span style={{
color: "#faad14",
marginLeft: "20px"
marginLeft: "20px",
}}>{i18next.t("ldap:The Auto Sync option will sync all users to specify organization")}</span>
);
}

View File

@@ -23,7 +23,7 @@ class LdapListPage extends React.Component {
constructor(props) {
super(props);
this.state = {
ldaps: null
ldaps: null,
};
}
@@ -65,7 +65,7 @@ class LdapListPage extends React.Component {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Organization"),
@@ -79,7 +79,7 @@ class LdapListPage extends React.Component {
{text}
</Link>
);
}
},
},
{
title: i18next.t("ldap:Server"),
@@ -89,7 +89,7 @@ class LdapListPage extends React.Component {
sorter: (a, b) => a.host.localeCompare(b.host),
render: (text, record, index) => {
return `${text}:${record.port}`;
}
},
},
{
title: i18next.t("ldap:Base DN"),
@@ -114,7 +114,7 @@ class LdapListPage extends React.Component {
render: (text, record, index) => {
return text === 0 ? (<span style={{color: "#faad14"}}>Disable</span>) : (
<span style={{color: "#52c41a"}}>{text + " mins"}</span>);
}
},
},
{
title: i18next.t("ldap:Last Sync"),
@@ -124,7 +124,7 @@ class LdapListPage extends React.Component {
sorter: (a, b) => a.lastSync.localeCompare(b.lastSync),
render: (text, record, index) => {
return text;
}
},
},
{
title: i18next.t("general:Action"),
@@ -148,7 +148,7 @@ class LdapListPage extends React.Component {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -87,7 +87,6 @@ class LdapSyncPage extends React.Component {
});
}
getLdapUser(ldap) {
LdapBackend.getLdapUser(ldap)
.then((res) => {

View File

@@ -48,7 +48,7 @@ class LdapTable extends React.Component {
passwd: "123",
baseDn: "ou=People,dc=example,dc=com",
autosync: 0,
lastSync: ""
lastSync: "",
};
}
@@ -104,7 +104,7 @@ class LdapTable extends React.Component {
{text}
</Link>
);
}
},
},
{
title: i18next.t("ldap:Server"),
@@ -114,7 +114,7 @@ class LdapTable extends React.Component {
sorter: (a, b) => a.host.localeCompare(b.host),
render: (text, record, index) => {
return `${text}:${record.port}`;
}
},
},
{
title: i18next.t("ldap:Base DN"),
@@ -132,7 +132,7 @@ class LdapTable extends React.Component {
render: (text, record, index) => {
return text === 0 ? (<span style={{color: "#faad14"}}>Disable</span>) : (
<span style={{color: "#52c41a"}}>{text + " mins"}</span>);
}
},
},
{
title: i18next.t("ldap:Last Sync"),
@@ -142,7 +142,7 @@ class LdapTable extends React.Component {
sorter: (a, b) => a.lastSync.localeCompare(b.lastSync),
render: (text, record, index) => {
return text;
}
},
},
{
title: i18next.t("general:Action"),
@@ -166,7 +166,7 @@ class LdapTable extends React.Component {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -97,7 +97,7 @@ class ModelEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitModelEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteModel()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -76,7 +76,7 @@ class ModelListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -92,7 +92,7 @@ class ModelListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -102,7 +102,7 @@ class ModelListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -122,7 +122,7 @@ class ModelListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -143,7 +143,7 @@ class ModelListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -60,7 +60,7 @@ class OrganizationEditPage extends React.Component {
}
}
this.setState({
ldaps: resdata
ldaps: resdata,
});
});
}
@@ -91,7 +91,7 @@ class OrganizationEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitOrganizationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteOrganization()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :

View File

@@ -112,7 +112,7 @@ class OrganizationListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -122,7 +122,7 @@ class OrganizationListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -143,7 +143,7 @@ class OrganizationListPage extends BaseListPage {
<img src={text} alt={text} width={40} />
</a>
);
}
},
},
{
title: i18next.t("organization:Website URL"),
@@ -158,7 +158,7 @@ class OrganizationListPage extends BaseListPage {
{text}
</a>
);
}
},
},
{
title: i18next.t("general:Password type"),
@@ -192,7 +192,7 @@ class OrganizationListPage extends BaseListPage {
<img src={text} alt={text} width={40} />
</a>
);
}
},
},
{
title: i18next.t("organization:Soft deletion"),
@@ -204,7 +204,7 @@ class OrganizationListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -226,7 +226,7 @@ class OrganizationListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -152,7 +152,7 @@ class PaymentEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitPaymentEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deletePayment()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -89,7 +89,7 @@ class PaymentListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:User"),
@@ -104,7 +104,7 @@ class PaymentListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -120,7 +120,7 @@ class PaymentListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -130,7 +130,7 @@ class PaymentListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
// {
// title: i18next.t("general:Display name"),
@@ -154,7 +154,7 @@ class PaymentListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("payment:Type"),
@@ -163,12 +163,12 @@ class PaymentListPage extends BaseListPage {
width: "140px",
align: "center",
filterMultiple: false,
filters: Setting.getProviderTypeOptions("Payment").map((o) => {return {text:o.id, value:o.name};}),
filters: Setting.getProviderTypeOptions("Payment").map((o) => {return {text: o.id, value: o.name};}),
sorter: true,
render: (text, record, index) => {
record.category = "Payment";
return Provider.getProviderLogoWidget(record);
}
},
},
{
title: i18next.t("payment:Product"),
@@ -221,7 +221,7 @@ class PaymentListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -67,7 +67,7 @@ class PaymentResultPage extends React.Component {
Setting.goToLink(payment.returnUrl);
}}>
{i18next.t("payment:Return to Website")}
</Button>
</Button>,
]}
/>
</div>
@@ -103,7 +103,7 @@ class PaymentResultPage extends React.Component {
Setting.goToLink(payment.returnUrl);
}}>
{i18next.t("payment:Return to Website")}
</Button>
</Button>,
]}
/>
</div>

View File

@@ -132,7 +132,7 @@ class PermissionEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deletePermission()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -81,7 +81,7 @@ class PermissionListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -97,7 +97,7 @@ class PermissionListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -107,7 +107,7 @@ class PermissionListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -126,7 +126,7 @@ class PermissionListPage extends BaseListPage {
...this.getColumnSearchProps("users"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("role:Sub roles"),
@@ -137,7 +137,7 @@ class PermissionListPage extends BaseListPage {
...this.getColumnSearchProps("roles"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("permission:Resource type"),
@@ -159,7 +159,7 @@ class PermissionListPage extends BaseListPage {
...this.getColumnSearchProps("resources"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("permission:Actions"),
@@ -170,7 +170,7 @@ class PermissionListPage extends BaseListPage {
...this.getColumnSearchProps("actions"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("permission:Effect"),
@@ -194,7 +194,7 @@ class PermissionListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -214,7 +214,7 @@ class PermissionListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -85,7 +85,7 @@ class ProductEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitProductEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteProduct()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
@@ -110,7 +110,7 @@ class ProductEditPage extends React.Component {
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("product:Image"), i18next.t("product:Image - Tooltip"))} :
</Col>
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} :{}}>
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :

View File

@@ -84,7 +84,7 @@ class ProductListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -94,7 +94,7 @@ class ProductListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -115,7 +115,7 @@ class ProductListPage extends BaseListPage {
<img src={text} alt={text} width={150} />
</a>
);
}
},
},
{
title: i18next.t("product:Tag"),
@@ -240,7 +240,7 @@ class ProductListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -167,7 +167,7 @@ class ProviderEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitProviderEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteProvider()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
@@ -208,6 +208,8 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("domain", Setting.getFullServerUrl());
} else if (value === "SAML") {
this.updateProviderField("type", "Aliyun IDaaS");
} else if (value === "Payment") {
this.updateProviderField("type", "Alipay");
} else if (value === "Captcha") {
this.updateProviderField("type", "Default");
}
@@ -267,7 +269,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
{
this.state.provider.type !== "WeCom" ? null : (
this.state.provider.type !== "WeCom" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Method"), i18next.t("provider:Method - Tooltip"))} :
@@ -416,7 +418,7 @@ class ProviderEditPage extends React.Component {
)
}
{
this.state.provider.type !== "Adfs" && this.state.provider.type !== "Casdoor" && this.state.provider.type !== "Okta" ? null : (
this.state.provider.type !== "Adfs" && this.state.provider.type !== "Casdoor" && this.state.provider.type !== "Okta" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :

View File

@@ -85,7 +85,7 @@ class ProviderListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -95,7 +95,7 @@ class ProviderListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -128,17 +128,17 @@ class ProviderListPage extends BaseListPage {
align: "center",
filterMultiple: false,
filters: [
{text: "OAuth", value: "OAuth", children: Setting.getProviderTypeOptions("OAuth").map((o) => {return {text:o.id, value:o.name};})},
{text: "Email", value: "Email", children: Setting.getProviderTypeOptions("Email").map((o) => {return {text:o.id, value:o.name};})},
{text: "SMS", value: "SMS", children: Setting.getProviderTypeOptions("SMS").map((o) => {return {text:o.id, value:o.name};})},
{text: "Storage", value: "Storage", children: Setting.getProviderTypeOptions("Storage").map((o) => {return {text:o.id, value:o.name};})},
{text: "SAML", value: "SAML", children: Setting.getProviderTypeOptions("SAML").map((o) => {return {text:o.id, value:o.name};})},
{text: "Captcha", value: "Captcha", children: Setting.getProviderTypeOptions("Captcha").map((o) => {return {text:o.id, value:o.name};})},
{text: "OAuth", value: "OAuth", children: Setting.getProviderTypeOptions("OAuth").map((o) => {return {text: o.id, value: o.name};})},
{text: "Email", value: "Email", children: Setting.getProviderTypeOptions("Email").map((o) => {return {text: o.id, value: o.name};})},
{text: "SMS", value: "SMS", children: Setting.getProviderTypeOptions("SMS").map((o) => {return {text: o.id, value: o.name};})},
{text: "Storage", value: "Storage", children: Setting.getProviderTypeOptions("Storage").map((o) => {return {text: o.id, value: o.name};})},
{text: "SAML", value: "SAML", children: Setting.getProviderTypeOptions("SAML").map((o) => {return {text: o.id, value: o.name};})},
{text: "Captcha", value: "Captcha", children: Setting.getProviderTypeOptions("Captcha").map((o) => {return {text: o.id, value: o.name};})},
],
sorter: true,
render: (text, record, index) => {
return Provider.getProviderLogoWidget(record);
}
},
},
{
title: i18next.t("provider:Client ID"),
@@ -149,7 +149,7 @@ class ProviderListPage extends BaseListPage {
...this.getColumnSearchProps("clientId"),
render: (text, record, index) => {
return Setting.getShortText(text);
}
},
},
{
title: i18next.t("provider:Provider URL"),
@@ -166,7 +166,7 @@ class ProviderListPage extends BaseListPage {
}
</a>
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -186,7 +186,7 @@ class ProviderListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -82,7 +82,7 @@ class ProviderTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("provider:Category"),
@@ -92,7 +92,7 @@ class ProviderTable extends React.Component {
render: (text, record, index) => {
const provider = Setting.getArrayItem(this.props.providers, "name", record.name);
return provider?.category;
}
},
},
{
title: i18next.t("provider:Type"),
@@ -102,7 +102,7 @@ class ProviderTable extends React.Component {
render: (text, record, index) => {
const provider = Setting.getArrayItem(this.props.providers, "name", record.name);
return Provider.getProviderLogoWidget(provider);
}
},
},
{
title: i18next.t("provider:canSignUp"),
@@ -119,7 +119,7 @@ class ProviderTable extends React.Component {
this.updateField(table, index, "canSignUp", checked);
}} />
);
}
},
},
{
title: i18next.t("provider:canSignIn"),
@@ -136,7 +136,7 @@ class ProviderTable extends React.Component {
this.updateField(table, index, "canSignIn", checked);
}} />
);
}
},
},
{
title: i18next.t("provider:canUnlink"),
@@ -153,7 +153,7 @@ class ProviderTable extends React.Component {
this.updateField(table, index, "canUnlink", checked);
}} />
);
}
},
},
{
title: i18next.t("provider:prompted"),
@@ -170,7 +170,7 @@ class ProviderTable extends React.Component {
this.updateField(table, index, "prompted", checked);
}} />
);
}
},
},
// {
// title: i18next.t("provider:alertType"),
@@ -211,7 +211,7 @@ class ProviderTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -32,7 +32,7 @@ class RecordListPage extends BaseListPage {
return {
owner: "built-in",
name: "1234",
id : "1234",
id: "1234",
clientIp: "::1",
timestamp: moment().format(),
organization: "built-in",
@@ -74,7 +74,7 @@ class RecordListPage extends BaseListPage {
{text}
</a>
);
}
},
},
{
title: i18next.t("general:Timestamp"),
@@ -84,7 +84,7 @@ class RecordListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Organization"),
@@ -99,7 +99,7 @@ class RecordListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:User"),
@@ -114,7 +114,7 @@ class RecordListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Method"),
@@ -153,7 +153,7 @@ class RecordListPage extends BaseListPage {
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return text;
}
},
},
{
title: i18next.t("record:Is Triggered"),
@@ -170,7 +170,7 @@ class RecordListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
];

View File

@@ -99,7 +99,7 @@ class ResourceListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("resource:Application"),
@@ -114,7 +114,7 @@ class ResourceListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("resource:User"),
@@ -129,7 +129,7 @@ class ResourceListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("resource:Parent"),
@@ -155,7 +155,7 @@ class ResourceListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("resource:Tag"),
@@ -196,7 +196,7 @@ class ResourceListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFriendlyFileSize(text);
}
},
},
{
title: i18next.t("general:Preview"),
@@ -219,7 +219,7 @@ class ResourceListPage extends BaseListPage {
</div>
);
}
}
},
},
{
title: i18next.t("general:URL"),
@@ -238,7 +238,7 @@ class ResourceListPage extends BaseListPage {
</Button>
</div>
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -260,7 +260,7 @@ class ResourceListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -107,7 +107,7 @@ class RoleEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitRoleEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteRole()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -77,7 +77,7 @@ class RoleListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -93,7 +93,7 @@ class RoleListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -103,7 +103,7 @@ class RoleListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -122,7 +122,7 @@ class RoleListPage extends BaseListPage {
...this.getColumnSearchProps("users"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("role:Sub roles"),
@@ -133,7 +133,7 @@ class RoleListPage extends BaseListPage {
...this.getColumnSearchProps("roles"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("general:Is enabled"),
@@ -145,7 +145,7 @@ class RoleListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -165,7 +165,7 @@ class RoleListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -75,35 +75,35 @@ export const OtherProviderInfo = {
},
"Azure Blob": {
logo: `${StaticBaseUrl}/img/social_azure.jpg`,
url: "https://azure.microsoft.com/en-us/services/storage/blobs/"
}
url: "https://azure.microsoft.com/en-us/services/storage/blobs/",
},
},
SAML: {
"Aliyun IDaaS": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
url: "https://aliyun.com/product/idaas"
url: "https://aliyun.com/product/idaas",
},
"Keycloak": {
logo: `${StaticBaseUrl}/img/social_keycloak.png`,
url: "https://www.keycloak.org/"
url: "https://www.keycloak.org/",
},
},
Payment: {
"Alipay": {
logo: `${StaticBaseUrl}/img/payment_alipay.png`,
url: "https://www.alipay.com/"
url: "https://www.alipay.com/",
},
"WeChat Pay": {
logo: `${StaticBaseUrl}/img/payment_wechat_pay.png`,
url: "https://pay.weixin.qq.com/"
url: "https://pay.weixin.qq.com/",
},
"PayPal": {
logo: `${StaticBaseUrl}/img/payment_paypal.png`,
url: "https://www.paypal.com/"
url: "https://www.paypal.com/",
},
"GC": {
logo: `${StaticBaseUrl}/img/payment_gc.png`,
url: "https://gc.org"
url: "https://gc.org",
},
},
Captcha: {
@@ -122,8 +122,12 @@ export const OtherProviderInfo = {
"Aliyun Captcha": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
url: "https://help.aliyun.com/product/28308.html",
}
}
},
"GEETEST": {
logo: `${StaticBaseUrl}/img/social_geetest.png`,
url: "https://www.geetest.com",
},
},
};
export function getCountryRegionData() {
@@ -136,7 +140,7 @@ export function getCountryRegionData() {
countries.registerLocale(require("i18n-iso-countries/langs/" + language + ".json"));
var data = countries.getNames(language, {select: "official"});
var result = [];
for (var i in data) {result.push({code:i, name:data[i]});}
for (var i in data) {result.push({code: i, name: data[i]});}
return result;
}
@@ -301,7 +305,7 @@ export function isPromptAnswered(user, application) {
}
const providerItems = getAllPromptedProviderItems(application);
for (let i = 0; i < providerItems.length; i ++) {
for (let i = 0; i < providerItems.length; i++) {
if (!isProviderItemAnswered(user, application, providerItems[i])) {
return false;
}
@@ -428,7 +432,7 @@ export function getShortName(s) {
return s.split("/").slice(-1)[0];
}
export function getShortText(s, maxLength=35) {
export function getShortText(s, maxLength = 35) {
if (s.length > maxLength) {
return `${s.slice(0, maxLength)}...`;
} else {
@@ -445,13 +449,13 @@ export function getFriendlyFileSize(size) {
let num = (size / Math.pow(1024, i));
let round = Math.round(num);
num = round < 10 ? num.toFixed(2) : round < 100 ? num.toFixed(1) : round;
return `${num} ${"KMGTPEZY"[i-1]}B`;
return `${num} ${"KMGTPEZY"[i - 1]}B`;
}
function getRandomInt(s) {
let hash = 0;
if (s.length !== 0) {
for (let i = 0; i < s.length; i ++) {
for (let i = 0; i < s.length; i++) {
let char = s.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
@@ -594,7 +598,7 @@ export function getProviderTypeOptions(category) {
{id: "AWS S3", name: "AWS S3"},
{id: "Aliyun OSS", name: "Aliyun OSS"},
{id: "Tencent Cloud COS", name: "Tencent Cloud COS"},
{id: "Azure Blob", name: "Azure Blob"}
{id: "Azure Blob", name: "Azure Blob"},
]
);
} else if (category === "SAML") {
@@ -615,6 +619,7 @@ export function getProviderTypeOptions(category) {
{id: "reCAPTCHA", name: "reCAPTCHA"},
{id: "hCaptcha", name: "hCaptcha"},
{id: "Aliyun Captcha", name: "Aliyun Captcha"},
{id: "GEETEST", name: "GEETEST"},
]);
} else {
return [];
@@ -718,7 +723,7 @@ export function goToForget(ths, application) {
}
export function renderHelmet(application) {
if (application === undefined || application === null || application.organizationObj === undefined || application.organizationObj === null ||application.organizationObj === "") {
if (application === undefined || application === null || application.organizationObj === undefined || application.organizationObj === null || application.organizationObj === "") {
return null;
}
@@ -786,7 +791,7 @@ export function getDeduplicatedArray(array, filterArray, key) {
export function getNewRowNameForTable(table, rowName) {
const emptyCount = table.filter(row => row.name.includes(rowName)).length;
let res = rowName;
for (let i = 0; i < emptyCount; i ++) {
for (let i = 0; i < emptyCount; i++) {
res = res + " ";
}
return res;
@@ -847,86 +852,86 @@ export function getSyncerTableColumns(syncer) {
case "Keycloak":
return [
{
"name":"ID",
"type":"string",
"casdoorName":"Id",
"isHashed":true,
"values":[
"name": "ID",
"type": "string",
"casdoorName": "Id",
"isHashed": true,
"values": [
]
],
},
{
"name":"USERNAME",
"type":"string",
"casdoorName":"Name",
"isHashed":true,
"values":[
"name": "USERNAME",
"type": "string",
"casdoorName": "Name",
"isHashed": true,
"values": [
]
],
},
{
"name":"LAST_NAME+FIRST_NAME",
"type":"string",
"casdoorName":"DisplayName",
"isHashed":true,
"values":[
"name": "LAST_NAME+FIRST_NAME",
"type": "string",
"casdoorName": "DisplayName",
"isHashed": true,
"values": [
]
],
},
{
"name":"EMAIL",
"type":"string",
"casdoorName":"Email",
"isHashed":true,
"values":[
"name": "EMAIL",
"type": "string",
"casdoorName": "Email",
"isHashed": true,
"values": [
]
],
},
{
"name":"EMAIL_VERIFIED",
"type":"boolean",
"casdoorName":"EmailVerified",
"isHashed":true,
"values":[
"name": "EMAIL_VERIFIED",
"type": "boolean",
"casdoorName": "EmailVerified",
"isHashed": true,
"values": [
]
],
},
{
"name":"FIRST_NAME",
"type":"string",
"casdoorName":"FirstName",
"isHashed":true,
"values":[
"name": "FIRST_NAME",
"type": "string",
"casdoorName": "FirstName",
"isHashed": true,
"values": [
]
],
},
{
"name":"LAST_NAME",
"type":"string",
"casdoorName":"LastName",
"isHashed":true,
"values":[
"name": "LAST_NAME",
"type": "string",
"casdoorName": "LastName",
"isHashed": true,
"values": [
]
],
},
{
"name":"CREATED_TIMESTAMP",
"type":"string",
"casdoorName":"CreatedTime",
"isHashed":true,
"values":[
"name": "CREATED_TIMESTAMP",
"type": "string",
"casdoorName": "CreatedTime",
"isHashed": true,
"values": [
]
],
},
{
"name":"ENABLED",
"type":"boolean",
"casdoorName":"IsForbidden",
"isHashed":true,
"values":[
"name": "ENABLED",
"type": "boolean",
"casdoorName": "IsForbidden",
"isHashed": true,
"values": [
]
}
],
},
];
default:
return [];

View File

@@ -101,7 +101,7 @@ class SignupTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("provider:visible"),
@@ -123,7 +123,7 @@ class SignupTable extends React.Component {
}
}} />
);
}
},
},
{
title: i18next.t("provider:required"),
@@ -140,7 +140,7 @@ class SignupTable extends React.Component {
this.updateField(table, index, "required", checked);
}} />
);
}
},
},
{
title: i18next.t("provider:prompted"),
@@ -161,7 +161,7 @@ class SignupTable extends React.Component {
this.updateField(table, index, "prompted", checked);
}} />
);
}
},
},
{
title: i18next.t("application:rule"),
@@ -201,7 +201,7 @@ class SignupTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -221,7 +221,7 @@ class SignupTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -89,7 +89,7 @@ class SyncerEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitSyncerEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteSyncer()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -101,7 +101,7 @@ class SyncerListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -117,7 +117,7 @@ class SyncerListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -127,7 +127,7 @@ class SyncerListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("provider:Type"),
@@ -212,7 +212,7 @@ class SyncerListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -233,7 +233,7 @@ class SyncerListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -73,7 +73,7 @@ class SyncerTableColumnTable extends React.Component {
this.updateField(table, index, "name", e.target.value);
}} />
);
}
},
},
{
title: i18next.t("syncer:Column type"),
@@ -88,7 +88,7 @@ class SyncerTableColumnTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("syncer:Casdoor column"),
@@ -105,7 +105,7 @@ class SyncerTableColumnTable extends React.Component {
}
</Select>
);
}
},
},
{
title: i18next.t("syncer:Is hashed"),
@@ -117,7 +117,7 @@ class SyncerTableColumnTable extends React.Component {
this.updateField(table, index, "isHashed", checked);
}} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -137,7 +137,7 @@ class SyncerTableColumnTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -54,6 +54,6 @@ function testEmailProvider(provider, email = "") {
return fetch(`${Setting.ServerUrl}/api/send-email`, {
method: "POST",
credentials: "include",
body: JSON.stringify(emailForm)
body: JSON.stringify(emailForm),
}).then(res => res.json());
}

View File

@@ -68,7 +68,7 @@ class TokenEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitTokenEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteToken()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Name")}:

View File

@@ -81,7 +81,7 @@ class TokenListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -91,7 +91,7 @@ class TokenListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Application"),
@@ -106,7 +106,7 @@ class TokenListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Organization"),
@@ -121,7 +121,7 @@ class TokenListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:User"),
@@ -136,7 +136,7 @@ class TokenListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("token:Authorization code"),
@@ -147,7 +147,7 @@ class TokenListPage extends BaseListPage {
...this.getColumnSearchProps("code"),
render: (text, record, index) => {
return Setting.getClickable(text);
}
},
},
{
title: i18next.t("token:Access token"),
@@ -159,7 +159,7 @@ class TokenListPage extends BaseListPage {
...this.getColumnSearchProps("accessToken"),
render: (text, record, index) => {
return Setting.getClickable(text);
}
},
},
{
title: i18next.t("token:Expires in"),
@@ -202,7 +202,7 @@ class TokenListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -71,7 +71,7 @@ class UrlTable extends React.Component {
this.updateField(table, index, e.target.value);
}} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -91,7 +91,7 @@ class UrlTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -466,7 +466,7 @@ class UserEditPage extends React.Component {
(this.state.application === null || this.state.user === null) ? null : (
this.state.application?.providers.filter(providerItem => Setting.isProviderVisible(providerItem)).map((providerItem, index) =>
(providerItem.provider.category === "OAuth") ? (
<OAuthWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => {return this.unlinked();}} />
<OAuthWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} account={this.props.account} onUnlinked={() => {return this.unlinked();}} />
) : (
<SamlWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => {return this.unlinked();}} />
)
@@ -567,7 +567,7 @@ class UserEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitUserEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteUser()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
{
this.state.application?.organizationObj.accountItems?.map(accountItem => {
return (

View File

@@ -152,7 +152,7 @@ class UserListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Application"),
@@ -168,7 +168,7 @@ class UserListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -184,7 +184,7 @@ class UserListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -194,7 +194,7 @@ class UserListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("general:Display name"),
@@ -215,7 +215,7 @@ class UserListPage extends BaseListPage {
<img src={text} alt={text} width={50} />
</a>
);
}
},
},
{
title: i18next.t("general:Email"),
@@ -230,7 +230,7 @@ class UserListPage extends BaseListPage {
{text}
</a>
);
}
},
},
{
title: i18next.t("general:Phone"),
@@ -281,7 +281,7 @@ class UserListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("user:Is global admin"),
@@ -293,7 +293,7 @@ class UserListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("user:Is forbidden"),
@@ -305,7 +305,7 @@ class UserListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("user:Is deleted"),
@@ -317,7 +317,7 @@ class UserListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -337,7 +337,7 @@ class UserListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -35,8 +35,8 @@ class WebAuthnCredentialTable extends React.Component {
{i18next.t("general:Delete")}
</Button>
);
}
}
},
},
];
return (

View File

@@ -84,8 +84,8 @@ const userTemplate = {
"phoneVerifiedTime": "",
"renameQuota": "3",
"tagline": "",
"website": ""
}
"website": "",
},
};
class WebhookEditPage extends React.Component {
@@ -155,7 +155,7 @@ class WebhookEditPage extends React.Component {
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitWebhookEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteWebhook()}>{i18next.t("general:Cancel")}</Button> : null}
</div>
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
<Row style={{marginTop: "10px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :

View File

@@ -72,7 +72,7 @@ class WebhookHeaderTable extends React.Component {
this.updateField(table, index, "name", e.target.value);
}} />
);
}
},
},
{
title: i18next.t("webhook:Value"),
@@ -84,7 +84,7 @@ class WebhookHeaderTable extends React.Component {
this.updateField(table, index, "value", e.target.value);
}} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -104,7 +104,7 @@ class WebhookHeaderTable extends React.Component {
</Tooltip>
</div>
);
}
},
},
];

View File

@@ -80,7 +80,7 @@ class WebhookListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Name"),
@@ -96,7 +96,7 @@ class WebhookListPage extends BaseListPage {
{text}
</Link>
);
}
},
},
{
title: i18next.t("general:Created time"),
@@ -106,7 +106,7 @@ class WebhookListPage extends BaseListPage {
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
},
},
{
title: i18next.t("webhook:URL"),
@@ -123,7 +123,7 @@ class WebhookListPage extends BaseListPage {
}
</a>
);
}
},
},
{
title: i18next.t("webhook:Method"),
@@ -143,7 +143,7 @@ class WebhookListPage extends BaseListPage {
filters: [
{text: "application/json", value: "application/json"},
{text: "application/x-www-form-urlencoded", value: "application/x-www-form-urlencoded"},
]
],
},
{
title: i18next.t("webhook:Events"),
@@ -154,7 +154,7 @@ class WebhookListPage extends BaseListPage {
...this.getColumnSearchProps("events"),
render: (text, record, index) => {
return Setting.getTags(text);
}
},
},
{
title: i18next.t("webhook:Is user extended"),
@@ -166,7 +166,7 @@ class WebhookListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Is enabled"),
@@ -178,7 +178,7 @@ class WebhookListPage extends BaseListPage {
return (
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
);
}
},
},
{
title: i18next.t("general:Action"),
@@ -198,7 +198,7 @@ class WebhookListPage extends BaseListPage {
</Popconfirm>
</div>
);
}
},
},
];

View File

@@ -17,7 +17,7 @@ import {authConfig} from "./Auth";
export function getAccount(query) {
return fetch(`${authConfig.serverUrl}/api/get-account${query}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -96,7 +96,7 @@ class ForgetPage extends React.Component {
AuthBackend.getEmailAndPhone({
application: forms.step1.getFieldValue("application"),
organization: forms.step1.getFieldValue("organization"),
username: username
username: username,
}).then((res) => {
if (res.status === "ok") {
const phone = res.data.phone;
@@ -147,7 +147,7 @@ class ForgetPage extends React.Component {
name: this.state.name,
code: forms.step2.getFieldValue("emailCode"),
phonePrefix: this.state.application?.organizationObj.phonePrefix,
type: "login"
type: "login",
}, oAuthParams).then(res => {
if (res.status === "ok") {
this.setState({current: 2, userId: res.data, username: res.data.split("/")[1]});
@@ -468,7 +468,7 @@ class ForgetPage extends React.Component {
</Form.Item>
<br />
<Form.Item hidden={this.state.current !== 2}>
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}>
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}>
{i18next.t("forget:Change Password")}
</Button>
</Form.Item>

View File

@@ -20,35 +20,13 @@ import * as UserWebauthnBackend from "../backend/UserWebauthnBackend";
import * as AuthBackend from "./AuthBackend";
import * as ApplicationBackend from "../backend/ApplicationBackend";
import * as Provider from "./Provider";
import * as ProviderButton from "./ProviderButton";
import * as Util from "./Util";
import * as Setting from "../Setting";
import SelfLoginButton from "./SelfLoginButton";
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
import FacebookLoginButton from "./FacebookLoginButton";
import QqLoginButton from "./QqLoginButton";
import DingTalkLoginButton from "./DingTalkLoginButton";
import GiteeLoginButton from "./GiteeLoginButton";
import WechatLoginButton from "./WechatLoginButton";
import WeiboLoginButton from "./WeiboLoginButton";
import i18next from "i18next";
import LinkedInLoginButton from "./LinkedInLoginButton";
import WeComLoginButton from "./WeComLoginButton";
import LarkLoginButton from "./LarkLoginButton";
import GitLabLoginButton from "./GitLabLoginButton";
import AdfsLoginButton from "./AdfsLoginButton";
import BaiduLoginButton from "./BaiduLoginButton";
import AlipayLoginButton from "./AlipayLoginButton";
import CasdoorLoginButton from "./CasdoorLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton";
import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import OktaLoginButton from "./OktaLoginButton";
import DouyinLoginButton from "./DouyinLoginButton";
import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput";
import BilibiliLoginButton from "./BilibiliLoginButton";
const {TabPane} = Tabs;
@@ -59,7 +37,7 @@ class LoginPage extends React.Component {
classes: props,
type: props.type,
applicationName: props.applicationName !== undefined ? props.applicationName : (props.match === undefined ? null : props.match.params.applicationName),
owner : props.owner !== undefined ? props.owner : (props.match === undefined ? null : props.match.params.owner),
owner: props.owner !== undefined ? props.owner : (props.match === undefined ? null : props.match.params.owner),
application: null,
mode: props.mode !== undefined ? props.mode : (props.match === undefined ? null : props.match.params.mode), // "signup" or "signin"
isCodeSignin: false,
@@ -68,7 +46,7 @@ class LoginPage extends React.Component {
validEmailOrPhone: false,
validEmail: false,
validPhone: false,
loginMethod: "password"
loginMethod: "password",
};
if (this.state.type === "cas" && props.match?.params.casApplicationName !== undefined) {
@@ -146,6 +124,16 @@ class LoginPage extends React.Component {
}
onFinish(values) {
if (this.state.loginMethod === "webAuthn") {
let username = this.state.username;
if (username === null || username === "") {
username = values["username"];
}
this.signInWithWebAuthn(username);
return;
}
const application = this.getApplicationObj();
const ths = this;
@@ -260,61 +248,6 @@ class LoginPage extends React.Component {
}
}
getSigninButton(type) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", type);
if (type === "GitHub") {
return <GithubLoginButton text={text} align={"center"} />;
} else if (type === "Google") {
return <GoogleLoginButton text={text} align={"center"} />;
} else if (type === "QQ") {
return <QqLoginButton text={text} align={"center"} />;
} else if (type === "Facebook") {
return <FacebookLoginButton text={text} align={"center"} />;
} else if (type === "Weibo") {
return <WeiboLoginButton text={text} align={"center"} />;
} else if (type === "Gitee") {
return <GiteeLoginButton text={text} align={"center"} />;
} else if (type === "WeChat") {
return <WechatLoginButton text={text} align={"center"} />;
} else if (type === "DingTalk") {
return <DingTalkLoginButton text={text} align={"center"} />;
} else if (type === "LinkedIn") {
return <LinkedInLoginButton text={text} align={"center"} />;
} else if (type === "WeCom") {
return <WeComLoginButton text={text} align={"center"} />;
} else if (type === "Lark") {
return <LarkLoginButton text={text} align={"center"} />;
} else if (type === "GitLab") {
return <GitLabLoginButton text={text} align={"center"} />;
} else if (type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} />;
} else if (type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />;
} else if (type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} />;
} else if (type === "Alipay") {
return <AlipayLoginButton text={text} align={"center"} />;
} else if (type === "Infoflow") {
return <InfoflowLoginButton text={text} align={"center"} />;
} else if (type === "Apple") {
return <AppleLoginButton text={text} align={"center"} />;
} else if (type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />;
} else if (type === "Bilibili") {
return <BilibiliLoginButton text={text} align={"center"} />;
} else if (type === "Okta") {
return <OktaLoginButton text={text} align={"center"} />;
} else if (type === "Douyin") {
return <DouyinLoginButton text={text} align={"center"} />;
}
return text;
}
getSamlUrl(provider) {
const params = new URLSearchParams(this.props.location.search);
let clientId = params.get("client_id");
@@ -332,35 +265,6 @@ class LoginPage extends React.Component {
});
}
renderProviderLogo(provider, application, width, margin, size) {
if (size === "small") {
if (provider.category === "OAuth") {
return (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")}>
<img width={width} height={width} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={this.getSamlUrl.bind(this, provider)}>
<img width={width} height={width} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
}
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
this.getSigninButton(provider.type)
}
</a>
</div>
);
}
}
isProviderVisible(providerItem) {
if (this.state.mode === "signup") {
return Setting.isProviderVisibleForSignUp(providerItem);
@@ -387,7 +291,7 @@ class LoginPage extends React.Component {
<Button type="primary" key="signin">
Sign In
</Button>
</Link>
</Link>,
]}
>
</Result>
@@ -435,7 +339,7 @@ class LoginPage extends React.Component {
rules={[
{
required: true,
message: i18next.t("login:Please input your username, Email or phone!")
message: i18next.t("login:Please input your username, Email or phone!"),
},
{
validator: (_, value) => {
@@ -455,8 +359,8 @@ class LoginPage extends React.Component {
this.setState({validEmailOrPhone: true});
return Promise.resolve();
}
}
},
},
]}
>
<Input
@@ -499,7 +403,12 @@ class LoginPage extends React.Component {
</Button>
) :
(
<Button type="primary" style={{width: "100%", marginBottom: "5px"}} onClick={() => this.signInWithWebAuthn()}>
<Button
type="primary"
htmlType="submit"
style={{width: "100%", marginBottom: "5px"}}
disabled={!application.enablePassword}
>
{i18next.t("login:Sign in with WebAuthn")}
</Button>
)
@@ -511,7 +420,7 @@ class LoginPage extends React.Component {
<Form.Item>
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return this.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
})
}
</Form.Item>
@@ -532,7 +441,7 @@ class LoginPage extends React.Component {
<br />
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return this.renderProviderLogo(providerItem.provider, application, 40, 10, "big");
return ProviderButton.renderProviderLogo(providerItem.provider, application, 40, 10, "big");
})
}
<div>
@@ -639,16 +548,16 @@ class LoginPage extends React.Component {
);
}
signInWithWebAuthn() {
if (this.state.username === null || this.state.username === "") {
signInWithWebAuthn(username) {
if (username === null || username === "") {
Setting.showMessage("error", "username is required for webauthn login");
return;
}
let application = this.getApplicationObj();
return fetch(`${Setting.ServerUrl}/api/webauthn/signin/begin?owner=${application.organization}&name=${this.state.username}`, {
return fetch(`${Setting.ServerUrl}/api/webauthn/signin/begin?owner=${application.organization}&name=${username}`, {
method: "GET",
credentials: "include"
credentials: "include",
})
.then(res => res.json())
.then((credentialRequestOptions) => {
@@ -657,13 +566,13 @@ class LoginPage extends React.Component {
throw credentialRequestOptions.status.msg;
}
credentialRequestOptions.certificate.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.certificate.challenge);
credentialRequestOptions.certificate.allowCredentials.forEach(function(listItem) {
credentialRequestOptions.publicKey.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.publicKey.challenge);
credentialRequestOptions.publicKey.allowCredentials.forEach(function(listItem) {
listItem.id = UserWebauthnBackend.webAuthnBufferDecode(listItem.id);
});
return navigator.credentials.get({
certificate: credentialRequestOptions.certificate
publicKey: credentialRequestOptions.publicKey,
});
})
.then((assertion) => {
@@ -685,7 +594,7 @@ class LoginPage extends React.Component {
signature: UserWebauthnBackend.webAuthnBufferEncode(sig),
userHandle: UserWebauthnBackend.webAuthnBufferEncode(userHandle),
},
})
}),
})
.then(res => res.json()).then((res) => {
if (res.msg === "") {

View File

@@ -117,7 +117,7 @@ class PromptPage extends React.Component {
<div>
{
(application === null || this.state.user === null) ? null : (
application?.providers.filter(providerItem => Setting.isProviderPrompted(providerItem)).map((providerItem, index) => <OAuthWidget key={providerItem.name} labelSpan={6} user={this.state.user} application={application} providerItem={providerItem} onUnlinked={() => {return this.unlinked();}} />)
application?.providers.filter(providerItem => Setting.isProviderPrompted(providerItem)).map((providerItem, index) => <OAuthWidget key={providerItem.name} labelSpan={6} user={this.state.user} application={application} providerItem={providerItem} account={this.props.account} onUnlinked={() => {return this.unlinked();}} />)
)
}
</div>
@@ -202,7 +202,7 @@ class PromptPage extends React.Component {
Setting.goToLogin(this, application);
}}>
Sign In
</Button>
</Button>,
]}
>
</Result>

View File

@@ -34,7 +34,7 @@ const authInfo = {
scope: "snsapi_login",
endpoint: "https://open.weixin.qq.com/connect/qrconnect",
mpScope: "snsapi_userinfo",
mpEndpoint: "https://open.weixin.qq.com/connect/oauth2/authorize"
mpEndpoint: "https://open.weixin.qq.com/connect/oauth2/authorize",
},
WeChatMiniProgram: {
endpoint: "https://mp.weixin.qq.com/",
@@ -119,8 +119,8 @@ const authInfo = {
endpoint: "https://example.com/",
},
Bilibili: {
endpoint: "https://passport.bilibili.com/register/pc_oauth2.html"
}
endpoint: "https://passport.bilibili.com/register/pc_oauth2.html",
},
};
export function getProviderUrl(provider) {

View File

@@ -0,0 +1,125 @@
// 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 i18next from "i18next";
import * as Provider from "./Provider";
import {getProviderLogoURL} from "../Setting";
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
import QqLoginButton from "./QqLoginButton";
import FacebookLoginButton from "./FacebookLoginButton";
import WeiboLoginButton from "./WeiboLoginButton";
import GiteeLoginButton from "./GiteeLoginButton";
import WechatLoginButton from "./WechatLoginButton";
import DingTalkLoginButton from "./DingTalkLoginButton";
import LinkedInLoginButton from "./LinkedInLoginButton";
import WeComLoginButton from "./WeComLoginButton";
import LarkLoginButton from "./LarkLoginButton";
import GitLabLoginButton from "./GitLabLoginButton";
import AdfsLoginButton from "./AdfsLoginButton";
import CasdoorLoginButton from "./CasdoorLoginButton";
import BaiduLoginButton from "./BaiduLoginButton";
import AlipayLoginButton from "./AlipayLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton";
import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import BilibiliLoginButton from "./BilibiliLoginButton";
import OktaLoginButton from "./OktaLoginButton";
import DouyinLoginButton from "./DouyinLoginButton";
function getSigninButton(type) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", type);
if (type === "GitHub") {
return <GithubLoginButton text={text} align={"center"} />;
} else if (type === "Google") {
return <GoogleLoginButton text={text} align={"center"} />;
} else if (type === "QQ") {
return <QqLoginButton text={text} align={"center"} />;
} else if (type === "Facebook") {
return <FacebookLoginButton text={text} align={"center"} />;
} else if (type === "Weibo") {
return <WeiboLoginButton text={text} align={"center"} />;
} else if (type === "Gitee") {
return <GiteeLoginButton text={text} align={"center"} />;
} else if (type === "WeChat") {
return <WechatLoginButton text={text} align={"center"} />;
} else if (type === "DingTalk") {
return <DingTalkLoginButton text={text} align={"center"} />;
} else if (type === "LinkedIn") {
return <LinkedInLoginButton text={text} align={"center"} />;
} else if (type === "WeCom") {
return <WeComLoginButton text={text} align={"center"} />;
} else if (type === "Lark") {
return <LarkLoginButton text={text} align={"center"} />;
} else if (type === "GitLab") {
return <GitLabLoginButton text={text} align={"center"} />;
} else if (type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} />;
} else if (type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />;
} else if (type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} />;
} else if (type === "Alipay") {
return <AlipayLoginButton text={text} align={"center"} />;
} else if (type === "Infoflow") {
return <InfoflowLoginButton text={text} align={"center"} />;
} else if (type === "Apple") {
return <AppleLoginButton text={text} align={"center"} />;
} else if (type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />;
} else if (type === "Bilibili") {
return <BilibiliLoginButton text={text} align={"center"} />;
} else if (type === "Okta") {
return <OktaLoginButton text={text} align={"center"} />;
} else if (type === "Douyin") {
return <DouyinLoginButton text={text} align={"center"} />;
}
return text;
}
export function renderProviderLogo(provider, application, width, margin, size) {
if (size === "small") {
if (provider.category === "OAuth") {
return (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")}>
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={this.getSamlUrl.bind(this, provider)}>
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
}
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
getSigninButton(provider.type)
}
</a>
</div>
);
}
}

View File

@@ -73,7 +73,7 @@ class ResultPage extends React.Component {
}
}}>
{i18next.t("login:Sign In")}
</Button>
</Button>,
]}
/>
</div>

View File

@@ -17,6 +17,7 @@ import {Link} from "react-router-dom";
import {Button, Checkbox, Col, Form, Input, Modal, Result, Row} from "antd";
import * as Setting from "../Setting";
import * as AuthBackend from "./AuthBackend";
import * as ProviderButton from "./ProviderButton";
import i18next from "i18next";
import * as Util from "./Util";
import {authConfig} from "./Auth";
@@ -179,6 +180,14 @@ class SignupPage extends React.Component {
this.form.current.scrollToField(errorFields[0].name);
}
isProviderVisible(providerItem) {
if (this.state.mode === "signup") {
return Setting.isProviderVisibleForSignUp(providerItem);
} else {
return Setting.isProviderVisibleForSignIn(providerItem);
}
}
renderFormItem(application, signupItem) {
if (!signupItem.visible) {
return null;
@@ -331,8 +340,8 @@ class SignupPage extends React.Component {
this.setState({validEmail: true});
return Promise.resolve();
}
}
},
},
]}
>
<Input onChange={e => this.setState({email: e.target.value})} />
@@ -377,8 +386,8 @@ class SignupPage extends React.Component {
this.setState({validPhone: true});
return Promise.resolve();
}
}
},
},
]}
>
<Input
@@ -521,7 +530,7 @@ class SignupPage extends React.Component {
Setting.goToLogin(this, application);
}}>
Sign In
</Button>
</Button>,
]}
>
</Result>
@@ -582,6 +591,11 @@ class SignupPage extends React.Component {
{i18next.t("signup:sign in now")}
</a>
</Form.Item>
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
})
}
</Form>
);
}
@@ -603,7 +617,7 @@ class SignupPage extends React.Component {
<CustomGithubCorner />
&nbsp;
<Row>
<Col span={24} style={{display: "flex", justifyContent: "center"}} >
<Col span={24} style={{display: "flex", justifyContent: "center"}} >
<div style={{marginTop: "10px", textAlign: "center"}}>
{
Setting.renderHelmet(application)

View File

@@ -76,7 +76,7 @@ export function renderMessageLarge(ths, msg) {
}
function getRefinedValue(value) {
return (value === null)? "" : value;
return (value === null) ? "" : value;
}
export function getCasParameters(params) {

View File

@@ -17,28 +17,28 @@ import * as Setting from "../Setting";
export function getApplications(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getApplicationsByOrganization(owner, organization) {
return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&organization=${organization}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getApplication(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-application?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getUserApplication(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-user-application?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
@@ -73,6 +73,6 @@ export function deleteApplication(application) {
export function getSamlMetadata(owner, name) {
return fetch(`${Setting.ServerUrl}/api/saml/metadata?application=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.text());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getCerts(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-certs?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getCert(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-cert?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getModels(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-models?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getModel(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-model?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getOrganizations(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-organizations?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getOrganization(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-organization?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getPayments(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-payments?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getPayment(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-payment?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
@@ -58,6 +58,6 @@ export function deletePayment(payment) {
export function invoicePayment(owner, name) {
return fetch(`${Setting.ServerUrl}/api/invoice-payment?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getPermissions(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-permissions?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getPermission(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-permission?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getProducts(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-products?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getProduct(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-product?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getProviders(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-providers?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getProvider(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-provider?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,6 +17,6 @@ import * as Setting from "../Setting";
export function getRecords(page, pageSize, field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-records?pageSize=${pageSize}&p=${page}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getResources(owner, user, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-resources?owner=${owner}&user=${user}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getResource(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-resource?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
@@ -46,7 +46,7 @@ export function addResource(resource) {
}).then(res => res.json());
}
export function deleteResource(resource, provider="") {
export function deleteResource(resource, provider = "") {
let newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/delete-resource?provider=${provider}`, {
method: "POST",
@@ -55,7 +55,7 @@ export function deleteResource(resource, provider="") {
}).then(res => res.json());
}
export function uploadResource(owner, user, tag, parent, fullFilePath, file, provider="") {
export function uploadResource(owner, user, tag, parent, fullFilePath, file, provider = "") {
const application = "app-built-in";
let formData = new FormData();
formData.append("file", file);

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getRoles(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-roles?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getRole(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-role?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getSyncers(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-syncers?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getSyncer(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-syncer?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getTokens(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-tokens?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getToken(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-token?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -18,21 +18,21 @@ import i18next from "i18next";
export function getGlobalUsers(page, pageSize, field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-global-users?p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getUsers(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-users?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getUser(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-user?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
@@ -84,7 +84,7 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
return fetch(`${Setting.ServerUrl}/api/set-password`, {
method: "POST",
credentials: "include",
body: formData
body: formData,
}).then(res => res.json());
}
@@ -100,7 +100,7 @@ export function sendCode(checkType, checkId, checkKey, dest, type, applicationId
return fetch(`${Setting.ServerUrl}/api/send-verification-code`, {
method: "POST",
credentials: "include",
body: formData
body: formData,
}).then(res => res.json()).then(res => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("user:Code Sent"));
@@ -120,7 +120,7 @@ export function verifyCaptcha(captchaType, captchaToken, clientSecret) {
return fetch(`${Setting.ServerUrl}/api/verify-captcha`, {
method: "POST",
credentials: "include",
body: formData
body: formData,
}).then(res => res.json()).then(res => {
if (res.status === "ok") {
if (res.data) {
@@ -144,12 +144,12 @@ export function resetEmailOrPhone(dest, type, code) {
return fetch(`${Setting.ServerUrl}/api/reset-email-or-phone`, {
method: "POST",
credentials: "include",
body: formData
body: formData,
}).then(res => res.json());
}
export function getCaptcha(owner, name, isCurrentProvider) {
return fetch(`${Setting.ServerUrl}/api/get-captcha?applicationId=${owner}/${encodeURIComponent(name)}&isCurrentProvider=${isCurrentProvider}`, {
method: "GET"
method: "GET",
}).then(res => res.json()).then(res => res.data);
}

View File

@@ -17,19 +17,19 @@ import * as Setting from "../Setting";
export function registerWebauthnCredential() {
return fetch(`${Setting.ServerUrl}/api/webauthn/signup/begin`, {
method: "GET",
credentials: "include"
credentials: "include",
})
.then(res => res.json())
.then((credentialCreationOptions) => {
credentialCreationOptions.certificate.challenge = webAuthnBufferDecode(credentialCreationOptions.certificate.challenge);
credentialCreationOptions.certificate.user.id = webAuthnBufferDecode(credentialCreationOptions.certificate.user.id);
if (credentialCreationOptions.certificate.excludeCredentials) {
for (var i = 0; i < credentialCreationOptions.certificate.excludeCredentials.length; i++) {
credentialCreationOptions.certificate.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.certificate.excludeCredentials[i].id);
credentialCreationOptions.publicKey.challenge = webAuthnBufferDecode(credentialCreationOptions.publicKey.challenge);
credentialCreationOptions.publicKey.user.id = webAuthnBufferDecode(credentialCreationOptions.publicKey.user.id);
if (credentialCreationOptions.publicKey.excludeCredentials) {
for (var i = 0; i < credentialCreationOptions.publicKey.excludeCredentials.length; i++) {
credentialCreationOptions.publicKey.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.publicKey.excludeCredentials[i].id);
}
}
return navigator.credentials.create({
certificate: credentialCreationOptions.certificate
publicKey: credentialCreationOptions.publicKey,
});
})
.then((credential) => {
@@ -47,7 +47,7 @@ export function registerWebauthnCredential() {
attestationObject: webAuthnBufferEncode(attestationObject),
clientDataJSON: webAuthnBufferEncode(clientDataJSON),
},
})
}),
})
.then(res => res.json());
});
@@ -61,7 +61,7 @@ export function deleteUserWebAuthnCredential(credentialID) {
method: "POST",
credentials: "include",
body: form,
dataType: "text"
dataType: "text",
}).then(res => res.json());
}

View File

@@ -17,14 +17,14 @@ import * as Setting from "../Setting";
export function getWebhooks(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-webhooks?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}
export function getWebhook(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-webhook?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include"
credentials: "include",
}).then(res => res.json());
}

View File

@@ -51,7 +51,7 @@ class HomePage extends React.Component {
{link: "/applications", name: i18next.t("general:Applications"), organizer: i18next.t("general:Applications that require authentication")},
];
for (let i = 0; i < items.length; i ++) {
for (let i = 0; i < items.length; i++) {
let filename = items[i].link;
if (filename === "/account") {
filename = "/users";
@@ -111,7 +111,7 @@ class HomePage extends React.Component {
return (
<div>
<Row style={{width: "100%"}}>
<Col span={24} style={{display: "flex", justifyContent: "center"}} >
<Col span={24} style={{display: "flex", justifyContent: "center"}} >
{
this.renderCards()
}

View File

@@ -25,7 +25,7 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
useEffect(() => {
switch (captchaType) {
case "reCAPTCHA":
case "reCAPTCHA": {
const reTimer = setInterval(() => {
if (!window.grecaptcha) {
loadScript("https://recaptcha.net/recaptcha/api.js");
@@ -39,7 +39,8 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
case "hCaptcha":
}
case "hCaptcha": {
const hTimer = setInterval(() => {
if (!window.hcaptcha) {
loadScript("https://js.hcaptcha.com/1/api.js");
@@ -53,7 +54,8 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
case "Aliyun Captcha":
}
case "Aliyun Captcha": {
const AWSCTimer = setInterval(() => {
if (!window.AWSC) {
loadScript("https://g.alicdn.com/AWSC/AWSC/awsc.js");
@@ -76,6 +78,33 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
}
case "GEETEST": {
let getLock = false;
const gTimer = setInterval(() => {
if (!window.initGeetest4) {
loadScript("https://static.geetest.com/v4/gt4.js");
}
if (window.initGeetest4 && siteKey && !getLock) {
const captchaId = String(siteKey);
window.initGeetest4({
captchaId,
product: "float",
}, function(captchaObj) {
if (!getLock) {
captchaObj.appendTo("#captcha");
getLock = true;
}
captchaObj.onSuccess(function() {
const result = captchaObj.getValidate();
onChange(`lot_number=${result.lot_number}&captcha_output=${result.captcha_output}&pass_token=${result.pass_token}&gen_time=${result.gen_time}&captcha_id=${siteKey}`);
});
});
clearInterval(gTimer);
}
}, 500);
break;
}
default:
break;
}

View File

@@ -104,7 +104,7 @@ export const CountDownInput = (props) => {
width: "200px",
borderRadius: "3px",
border: "1px solid #ccc",
marginBottom: 10
marginBottom: 10,
}}
/>
<Row>

View File

@@ -91,6 +91,8 @@ class OAuthWidget extends React.Component {
unlinkUser(providerType) {
const body = {
providerType: providerType,
// should add the unlink user's info, cause the user may not be logged in, but a admin want to unlink the user.
user: this.props.user,
};
AuthBackend.unlink(body)
.then((res) => {
@@ -113,6 +115,8 @@ class OAuthWidget extends React.Component {
const displayName = this.getUserProperty(user, provider.type, "displayName");
const email = this.getUserProperty(user, provider.type, "email");
let avatarUrl = this.getUserProperty(user, provider.type, "avatarUrl");
// the account user
const account = this.props.account;
if (avatarUrl === "" || avatarUrl === undefined) {
avatarUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAQAAACROWYpAAAAHElEQVR42mNkoAAwjmoe1TyqeVTzqOZRzcNZMwB18wAfEFQkPQAAAABJRU5ErkJggg==";
@@ -161,10 +165,10 @@ class OAuthWidget extends React.Component {
{
linkedValue === "" ? (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "link")}>
<Button style={{marginLeft: "20px", width: "80px"}} type="primary">{i18next.t("user:Link")}</Button>
<Button style={{marginLeft: "20px", width: "80px"}} type="primary" disabled={user.id !== account.id}>{i18next.t("user:Link")}</Button>
</a>
) : (
<Button disabled={!providerItem.canUnlink} style={{marginLeft: "20px", width: "80px"}} onClick={() => this.unlinkUser(provider.type)}>{i18next.t("user:Unlink")}</Button>
<Button disabled={!providerItem.canUnlink && !account.isGlobalAdmin} style={{marginLeft: "20px", width: "80px"}} onClick={() => this.unlinkUser(provider.type)}>{i18next.t("user:Unlink")}</Button>
)
}
</Col>