mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-19 08:20:33 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cba338eef2 | ||
![]() |
c428de6e42 | ||
![]() |
9bca6bb72e | ||
![]() |
cd966116d4 | ||
![]() |
9abf1b9d73 | ||
![]() |
6aaba6debd | ||
![]() |
77565712e0 | ||
![]() |
d025259db7 | ||
![]() |
aafdc546fa | ||
![]() |
539ca2d731 | ||
![]() |
ea326b3513 | ||
![]() |
98ef766fb4 | ||
![]() |
e94ada9ea2 | ||
![]() |
4ea482223d | ||
![]() |
d55ae7d1d2 | ||
![]() |
d72e00605f | ||
![]() |
be74cb621f | ||
![]() |
13404d6035 | ||
![]() |
afa9c530ad | ||
![]() |
1600615aca | ||
![]() |
2bb8491499 | ||
![]() |
293283ed25 | ||
![]() |
9cb519d1e9 | ||
![]() |
fb9b8f1662 |
82
captcha/geetest.go
Normal file
82
captcha/geetest.go
Normal 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)
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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
2
go.mod
@@ -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
2
go.sum
@@ -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=
|
||||
|
@@ -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"
|
||||
)
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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()
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -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",
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
"/cas/validate": {
|
||||
target: "http://localhost:8000",
|
||||
changeOrigin: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
@@ -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"
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"}}>
|
||||
{
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -87,7 +87,6 @@ class LdapSyncPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getLdapUser(ldap) {
|
||||
LdapBackend.getLdapUser(ldap)
|
||||
.then((res) => {
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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} />
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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 [];
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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")}:
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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 (
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -35,8 +35,8 @@ class WebAuthnCredentialTable extends React.Component {
|
||||
{i18next.t("general:Delete")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
@@ -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"))} :
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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 === "") {
|
||||
|
@@ -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>
|
||||
|
@@ -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) {
|
||||
|
125
web/src/auth/ProviderButton.js
Normal file
125
web/src/auth/ProviderButton.js
Normal 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>
|
||||
);
|
||||
}
|
||||
}
|
@@ -73,7 +73,7 @@ class ResultPage extends React.Component {
|
||||
}
|
||||
}}>
|
||||
{i18next.t("login:Sign In")}
|
||||
</Button>
|
||||
</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
@@ -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 />
|
||||
|
||||
<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)
|
||||
|
@@ -76,7 +76,7 @@ export function renderMessageLarge(ths, msg) {
|
||||
}
|
||||
|
||||
function getRefinedValue(value) {
|
||||
return (value === null)? "" : value;
|
||||
return (value === null) ? "" : value;
|
||||
}
|
||||
|
||||
export function getCasParameters(params) {
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -104,7 +104,7 @@ export const CountDownInput = (props) => {
|
||||
width: "200px",
|
||||
borderRadius: "3px",
|
||||
border: "1px solid #ccc",
|
||||
marginBottom: 10
|
||||
marginBottom: 10,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user