mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-31 08:50:31 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fdf2b880cb | ||
![]() |
80a2263b18 | ||
![]() |
1f11d22c1c | ||
![]() |
b6988286b5 | ||
![]() |
64f787fab5 | ||
![]() |
39c6bd5850 | ||
![]() |
7312c5ce3c | ||
![]() |
0bc5b90218 | ||
![]() |
f3b3376a3c | ||
![]() |
feec6abd88 | ||
![]() |
c50042c85a |
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -86,6 +86,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: master
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
|
@@ -19,6 +19,7 @@ RUN apk add curl
|
||||
RUN apk add ca-certificates && update-ca-certificates
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=BACK /go/src/casdoor/.git/refs/heads .git/refs/heads
|
||||
COPY --from=BACK /go/src/casdoor/server ./server
|
||||
COPY --from=BACK /go/src/casdoor/swagger ./swagger
|
||||
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf
|
||||
@@ -41,6 +42,7 @@ RUN apt update
|
||||
RUN apt install -y ca-certificates && update-ca-certificates
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=BACK /go/src/casdoor/.git/refs/heads .git/refs/heads
|
||||
COPY --from=BACK /go/src/casdoor/server ./server
|
||||
COPY --from=BACK /go/src/casdoor/swagger ./swagger
|
||||
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
|
||||
|
@@ -41,16 +41,19 @@ func (c *ApiController) GetSystemInfo() {
|
||||
user := object.GetUser(id)
|
||||
if user == nil || !user.IsGlobalAdmin {
|
||||
c.ResponseError("You are not authorized to access this resource")
|
||||
return
|
||||
}
|
||||
|
||||
cpuUsage, err := util.GetCpuUsage()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
memoryUsed, memoryTotal, err := util.GetMemoryUsage()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = SystemInfo{
|
||||
@@ -71,6 +74,7 @@ func (c *ApiController) GitRepoVersion() {
|
||||
version, err := util.GetGitRepoVersion()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = version
|
||||
|
3
go.mod
3
go.mod
@@ -33,11 +33,12 @@ require (
|
||||
github.com/russellhaering/goxmldsig v1.1.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/shirou/gopsutil/v3 v3.22.7 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/thanhpk/randstr v1.0.4
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||
|
8
go.sum
8
go.sum
@@ -156,6 +156,7 @@ github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ
|
||||
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
|
||||
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
|
||||
@@ -221,7 +222,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -300,7 +300,6 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
||||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro=
|
||||
@@ -344,7 +343,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
|
||||
@@ -383,8 +381,6 @@ github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil/v3 v3.22.7 h1:flKnuCMfUUrO+oAvwAd6GKZgnPzr098VA/UJ14nhJd4=
|
||||
github.com/shirou/gopsutil/v3 v3.22.7/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
|
||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||
@@ -432,6 +428,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@@ -576,7 +573,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
3
main.go
3
main.go
@@ -45,7 +45,8 @@ func main() {
|
||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||
|
||||
// beego.DelStaticPath("/static")
|
||||
beego.SetStaticPath("/static", "web/build/static")
|
||||
// beego.SetStaticPath("/static", "web/build/static")
|
||||
|
||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||
beego.SetStaticPath("/swagger", "swagger")
|
||||
beego.SetStaticPath("/files", "files")
|
||||
|
@@ -84,6 +84,7 @@ func initBuiltInOrganization() bool {
|
||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
},
|
||||
}
|
||||
AddOrganization(organization)
|
||||
|
@@ -46,7 +46,7 @@ type Organization struct {
|
||||
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
||||
IsProfilePublic bool `json:"isProfilePublic"`
|
||||
|
||||
AccountItems []*AccountItem `xorm:"varchar(2000)" json:"accountItems"`
|
||||
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
|
||||
}
|
||||
|
||||
func GetOrganizationCount(owner, field, value string) int {
|
||||
|
@@ -114,6 +114,8 @@ type User struct {
|
||||
|
||||
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||
|
||||
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
|
||||
}
|
||||
|
||||
type Userinfo struct {
|
||||
@@ -128,6 +130,13 @@ type Userinfo struct {
|
||||
Phone string `json:"phone,omitempty"`
|
||||
}
|
||||
|
||||
type ManagedAccount struct {
|
||||
Application string `xorm:"varchar(100)" json:"application"`
|
||||
Username string `xorm:"varchar(100)" json:"username"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
|
||||
}
|
||||
|
||||
func GetGlobalUserCount(field, value string) int {
|
||||
session := GetSession("", -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&User{})
|
||||
@@ -334,6 +343,12 @@ func GetMaskedUser(user *User) *User {
|
||||
if user.Password != "" {
|
||||
user.Password = "***"
|
||||
}
|
||||
|
||||
if user.ManagedAccounts != nil {
|
||||
for _, manageAccount := range user.ManagedAccounts {
|
||||
manageAccount.Password = "***"
|
||||
}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -378,7 +393,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
||||
columns = []string{
|
||||
"owner", "display_name", "avatar",
|
||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials",
|
||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||
"signin_wrong_times", "last_signin_wrong_time",
|
||||
}
|
||||
}
|
||||
|
@@ -16,12 +16,19 @@ package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
var (
|
||||
oldStaticBaseUrl = "https://cdn.casbin.org"
|
||||
newStaticBaseUrl = beego.AppConfig.String("staticBaseUrl")
|
||||
)
|
||||
|
||||
func StaticFilter(ctx *context.Context) {
|
||||
urlPath := ctx.Request.URL.Path
|
||||
if strings.HasPrefix(urlPath, "/api/") || strings.HasPrefix(urlPath, "/.well-known/") {
|
||||
@@ -38,9 +45,35 @@ func StaticFilter(ctx *context.Context) {
|
||||
path += urlPath
|
||||
}
|
||||
|
||||
if util.FileExist(path) {
|
||||
if !util.FileExist(path) {
|
||||
path = "web/build/index.html"
|
||||
}
|
||||
|
||||
if oldStaticBaseUrl == newStaticBaseUrl {
|
||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
|
||||
} else {
|
||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
|
||||
serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path, oldStaticBaseUrl, newStaticBaseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, old string, new string) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
oldContent := util.ReadStringFromPath(name)
|
||||
newContent := strings.ReplaceAll(oldContent, old, new)
|
||||
|
||||
http.ServeContent(w, r, d.Name(), d.ModTime(), strings.NewReader(newContent))
|
||||
_, err = w.Write([]byte(newContent))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
name="description"
|
||||
content="Casdoor - An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="https://cdn.casdoor.com/static/favicon.png" />
|
||||
<link rel="apple-touch-icon" href="https://cdn.casbin.org/img/favicon.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
|
@@ -95,6 +95,7 @@ class AccountTable extends React.Component {
|
||||
{name: "Is forbidden", displayName: i18next.t("user:Is forbidden")},
|
||||
{name: "Is deleted", displayName: i18next.t("user:Is deleted")},
|
||||
{name: "WebAuthn credentials", displayName: i18next.t("user:WebAuthn credentials")},
|
||||
{name: "Managed accounts", displayName: i18next.t("user:Managed accounts")},
|
||||
];
|
||||
|
||||
const getItemDisplayName = (text) => {
|
||||
|
165
web/src/ManagedAccountTable.js
Normal file
165
web/src/ManagedAccountTable.js
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
|
||||
import {Button, Col, Input, Row, Select, Table, Tooltip} from "antd";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
class ManagedAccountTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
};
|
||||
}
|
||||
|
||||
updateTable(table) {
|
||||
this.props.onUpdateTable(table);
|
||||
}
|
||||
|
||||
updateField(table, index, key, value) {
|
||||
table[index][key] = value;
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
addRow(table) {
|
||||
const row = {application: "", username: "", password: "", signinUrl: ""};
|
||||
if (table === undefined || table === null) {
|
||||
table = [];
|
||||
}
|
||||
table = Setting.addRow(table, row);
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
deleteRow(table, i) {
|
||||
table = Setting.deleteRow(table, i);
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
upRow(table, i) {
|
||||
table = Setting.swapRow(table, i - 1, i);
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
downRow(table, i) {
|
||||
table = Setting.swapRow(table, i, i + 1);
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
renderTable(table) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Application"),
|
||||
dataIndex: "application",
|
||||
key: "application",
|
||||
render: (text, record, index) => {
|
||||
const items = this.props.applications;
|
||||
const signinUrlMap = new Map();
|
||||
for (const application of items) {
|
||||
signinUrlMap.set(application.name, application.signinUrl);
|
||||
}
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
value={text}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "application", value);
|
||||
this.updateField(table, index, "signinUrl", signinUrlMap.get(value));
|
||||
}} >
|
||||
{
|
||||
items.map((item, index) => <Option key={index} value={item.name}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("signup:Username"),
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
width: "420px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input defaultValue={text} onChange={e => {
|
||||
this.updateField(table, index, "username", e.target.value);
|
||||
}} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Password"),
|
||||
dataIndex: "password",
|
||||
key: "password",
|
||||
width: "420px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input defaultValue={text} onChange={e => {
|
||||
this.updateField(table, index, "password", e.target.value);
|
||||
}} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
key: "action",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Tooltip placement="bottomLeft" title={i18next.t("general:Up")}>
|
||||
<Button style={{marginRight: "5px"}} disabled={index === 0} icon={<UpOutlined />} size="small" onClick={() => this.upRow(table, index)} />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={i18next.t("general:Down")}>
|
||||
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
|
||||
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Table scroll={{x: "max-content"}} rowKey="name" columns={columns} dataSource={table} size="middle" bordered pagination={false}
|
||||
title={() => (
|
||||
<div>
|
||||
{this.props.title}
|
||||
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col span={24}>
|
||||
{
|
||||
this.renderTable(this.props.table)
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ManagedAccountTable;
|
@@ -245,7 +245,8 @@ class PermissionEditPage extends React.Component {
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: "Application", name: "Application"},
|
||||
{id: "Application", name: i18next.t("general:Application")},
|
||||
{id: "TreeNode", name: i18next.t("permission:TreeNode")},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
@@ -273,9 +274,9 @@ class PermissionEditPage extends React.Component {
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: "Read", name: "Read"},
|
||||
{id: "Write", name: "Write"},
|
||||
{id: "Admin", name: "Admin"},
|
||||
{id: "Read", name: i18next.t("permission:Read")},
|
||||
{id: "Write", name: i18next.t("permission:Write")},
|
||||
{id: "Admin", name: i18next.t("permission:Admin")},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
@@ -291,8 +292,8 @@ class PermissionEditPage extends React.Component {
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: "Allow", name: "Allow"},
|
||||
{id: "Deny", name: "Deny"},
|
||||
{id: "Allow", name: i18next.t("permission:Allow")},
|
||||
{id: "Deny", name: i18next.t("permission:Deny")},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
@@ -358,8 +359,8 @@ class PermissionEditPage extends React.Component {
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: "Approved", name: "Approved"},
|
||||
{id: "Pending", name: "Pending"},
|
||||
{id: "Approved", name: i18next.t("permission:Approved")},
|
||||
{id: "Pending", name: i18next.t("permission:Pending")},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
@@ -374,10 +375,10 @@ class PermissionEditPage extends React.Component {
|
||||
Setting.showMessage("error", "The users and roles cannot be empty at the same time");
|
||||
return;
|
||||
}
|
||||
if (this.state.permission.domains.length === 0) {
|
||||
Setting.showMessage("error", "The domains cannot be empty");
|
||||
return;
|
||||
}
|
||||
// if (this.state.permission.domains.length === 0) {
|
||||
// Setting.showMessage("error", "The domains cannot be empty");
|
||||
// return;
|
||||
// }
|
||||
if (this.state.permission.resources.length === 0) {
|
||||
Setting.showMessage("error", "The resources cannot be empty");
|
||||
return;
|
||||
|
@@ -188,7 +188,19 @@ class PermissionListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("actions"),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
const tags = text.map((tag, i) => {
|
||||
switch (tag) {
|
||||
case "Read":
|
||||
return i18next.t("permission:Read");
|
||||
case "Write":
|
||||
return i18next.t("permission:Write");
|
||||
case "Admin":
|
||||
return i18next.t("permission:Admin");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return Setting.getTags(tags);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -197,11 +209,21 @@ class PermissionListPage extends BaseListPage {
|
||||
key: "effect",
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: "Allow", value: "Allow"},
|
||||
{text: "Deny", value: "Deny"},
|
||||
{text: i18next.t("permission:Allow"), value: "Allow"},
|
||||
{text: i18next.t("permission:Deny"), value: "Deny"},
|
||||
],
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
switch (text) {
|
||||
case "Allow":
|
||||
return Setting.getTag("success", i18next.t("permission:Allow"));
|
||||
case "Deny":
|
||||
return Setting.getTag("error", i18next.t("permission:Deny"));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Is enabled"),
|
||||
@@ -248,11 +270,21 @@ class PermissionListPage extends BaseListPage {
|
||||
key: "state",
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: "Approved", value: "Approved"},
|
||||
{text: "Pending", value: "Pending"},
|
||||
{text: i18next.t("permission:Approved"), value: "Approved"},
|
||||
{text: i18next.t("permission:Pending"), value: "Pending"},
|
||||
],
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
switch (text) {
|
||||
case "Approved":
|
||||
return Setting.getTag("success", i18next.t("permission:Approved"));
|
||||
case "Pending":
|
||||
return Setting.getTag("error", i18next.t("permission:Pending"));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
|
@@ -208,10 +208,18 @@ export function isProviderPrompted(providerItem) {
|
||||
return isProviderVisible(providerItem) && providerItem.prompted;
|
||||
}
|
||||
|
||||
export function isSignupItemPrompted(signupItem) {
|
||||
return signupItem.visible && signupItem.prompted;
|
||||
}
|
||||
|
||||
export function getAllPromptedProviderItems(application) {
|
||||
return application.providers.filter(providerItem => isProviderPrompted(providerItem));
|
||||
}
|
||||
|
||||
export function getAllPromptedSignupItems(application) {
|
||||
return application.signupItems.filter(signupItem => isSignupItemPrompted(signupItem));
|
||||
}
|
||||
|
||||
export function getSignupItem(application, itemName) {
|
||||
const signupItems = application.signupItems?.filter(signupItem => signupItem.name === itemName);
|
||||
if (signupItems.length === 0) {
|
||||
@@ -283,6 +291,11 @@ export function hasPromptPage(application) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const signupItems = getAllPromptedSignupItems(application);
|
||||
if (signupItems.length !== 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isAffiliationPrompted(application);
|
||||
}
|
||||
|
||||
@@ -307,6 +320,19 @@ function isProviderItemAnswered(user, application, providerItem) {
|
||||
return linkedValue !== undefined && linkedValue !== "";
|
||||
}
|
||||
|
||||
function isSignupItemAnswered(user, signupItem) {
|
||||
if (user === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (signupItem.name !== "Country/Region") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const value = user["region"];
|
||||
return value !== undefined && value !== "";
|
||||
}
|
||||
|
||||
export function isPromptAnswered(user, application) {
|
||||
if (!isAffiliationAnswered(user, application)) {
|
||||
return false;
|
||||
@@ -318,6 +344,13 @@ export function isPromptAnswered(user, application) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const signupItems = getAllPromptedSignupItems(application);
|
||||
for (let i = 0; i < signupItems.length; i++) {
|
||||
if (!isSignupItemAnswered(user, signupItems[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -824,7 +857,10 @@ export function getTagColor(s) {
|
||||
|
||||
export function getTags(tags) {
|
||||
const res = [];
|
||||
if (!tags) {return res;}
|
||||
if (!tags) {
|
||||
return res;
|
||||
}
|
||||
|
||||
tags.forEach((tag, i) => {
|
||||
res.push(
|
||||
<Tag color={getTagColor(tag)}>
|
||||
@@ -835,6 +871,14 @@ export function getTags(tags) {
|
||||
return res;
|
||||
}
|
||||
|
||||
export function getTag(color, text) {
|
||||
return (
|
||||
<Tag color={color}>
|
||||
{text}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
export function getApplicationOrgName(application) {
|
||||
return `${application?.organizationObj.owner}/${application?.organizationObj.name}`;
|
||||
}
|
||||
|
@@ -152,7 +152,7 @@ class SignupTable extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (record.visible) {
|
||||
if (record.visible && record.name !== "Country/Region") {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Card, Col, Divider, Progress, Row} from "antd";
|
||||
import {Card, Col, Divider, Progress, Row, Spin} from "antd";
|
||||
import * as SystemBackend from "./backend/SystemInfo";
|
||||
import React from "react";
|
||||
import * as Setting from "./Setting";
|
||||
@@ -26,8 +26,10 @@ class SystemInfo extends React.Component {
|
||||
cpuUsage: [],
|
||||
memUsed: 0,
|
||||
memTotal: 0,
|
||||
latestVersion: "v1.0.0",
|
||||
latestVersion: undefined,
|
||||
intervalId: null,
|
||||
href: "",
|
||||
loading: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,6 +39,7 @@ class SystemInfo extends React.Component {
|
||||
cpuUsage: res.cpu_usage,
|
||||
memUsed: res.memory_used,
|
||||
memTotal: res.memory_total,
|
||||
loading: false,
|
||||
});
|
||||
|
||||
const id = setInterval(() => {
|
||||
@@ -46,6 +49,8 @@ class SystemInfo extends React.Component {
|
||||
memUsed: res.memory_used,
|
||||
memTotal: res.memory_total,
|
||||
});
|
||||
}).catch(error => {
|
||||
Setting.showMessage("error", `System info failed to get: ${error}`);
|
||||
});
|
||||
}, 1000 * 3);
|
||||
this.setState({intervalId: id});
|
||||
@@ -54,17 +59,37 @@ class SystemInfo extends React.Component {
|
||||
});
|
||||
|
||||
SystemBackend.getGitHubLatestReleaseVersion().then(res => {
|
||||
this.setState({latestVersion: res});
|
||||
const href = res && res.length >= 8 ? `https://github.com/casdoor/casdoor/commit/${res}` : "";
|
||||
const versionText = res && res.length >= 8 ? res.substring(0, 8) : i18next.t("system:Unknown Version");
|
||||
this.setState({latestVersion: versionText, href: href});
|
||||
}).catch(err => {
|
||||
Setting.showMessage("error", `get latest commit version failed: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.state.intervalId);
|
||||
if (this.state.intervalId !== null) {
|
||||
clearInterval(this.state.intervalId);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const CPUInfo = this.state.cpuUsage?.length > 0 ?
|
||||
this.state.cpuUsage.map((usage, i) => {
|
||||
return (
|
||||
<Progress key={i} percent={Number(usage.toFixed(1))} />
|
||||
);
|
||||
}) : i18next.t("system:Get CPU Usage Failed");
|
||||
|
||||
const MemInfo = (
|
||||
this.state.memUsed && this.state.memTotal && this.state.memTotal !== 0 ?
|
||||
<div>
|
||||
{Setting.getFriendlyFileSize(this.state.memUsed)} / {Setting.getFriendlyFileSize(this.state.memTotal)}
|
||||
<br /> <br />
|
||||
<Progress type="circle" percent={Number((Number(this.state.memUsed) / Number(this.state.memTotal) * 100).toFixed(2))} />
|
||||
</div> : i18next.t("system:Get Memory Usage Failed")
|
||||
);
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col span={6}></Col>
|
||||
@@ -72,30 +97,21 @@ class SystemInfo extends React.Component {
|
||||
<Row gutter={[10, 10]}>
|
||||
<Col span={12}>
|
||||
<Card title={i18next.t("system:CPU Usage")} bordered={true} style={{textAlign: "center"}}>
|
||||
{
|
||||
this.state.cpuUsage.length !== 0 &&
|
||||
this.state.cpuUsage.map((usage, i) => {
|
||||
return (
|
||||
<Progress key={i} percent={Number(usage.toFixed(1))} />
|
||||
);
|
||||
})
|
||||
}
|
||||
{this.state.loading ? <Spin size="large" /> : CPUInfo}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card title={i18next.t("system:Memory Usage")} bordered={true} style={{textAlign: "center"}}>
|
||||
{(Number(this.state.memUsed) / 1024 / 1024).toFixed(2)} MB / {(Number(this.state.memTotal) / 1024 / 1024 / 1024).toFixed(2)} GB
|
||||
<br /> <br />
|
||||
<Progress type="circle" percent={Number((Number(this.state.memUsed) / Number(this.state.memTotal) * 100).toFixed(2))} />
|
||||
{this.state.loading ? <Spin size="large" /> : MemInfo}
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Divider />
|
||||
<Card title="About Casdoor" bordered={true} style={{textAlign: "center"}}>
|
||||
<Card title={i18next.t("system:About Casdoor")} bordered={true} style={{textAlign: "center"}}>
|
||||
<div>{i18next.t("system:An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS")}</div>
|
||||
GitHub: <a href="https://github.com/casdoor/casdoor">casdoor</a>
|
||||
<br />
|
||||
{i18next.t("system:Version")}: <a href={`https://github.com/casdoor/casdoor/commit/${this.state.latestVersion}`}>{this.state.latestVersion.substring(0, 8)}</a>
|
||||
{i18next.t("system:Version")}: <a href={this.state.href}>{this.state.latestVersion}</a>
|
||||
<br />
|
||||
{i18next.t("system:Official Website")}: <a href="https://casdoor.org/">casdoor.org</a>
|
||||
<br />
|
||||
|
@@ -28,6 +28,7 @@ import OAuthWidget from "./common/OAuthWidget";
|
||||
import SamlWidget from "./common/SamlWidget";
|
||||
import SelectRegionBox from "./SelectRegionBox";
|
||||
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
|
||||
import ManagedAccountTable from "./ManagedAccountTable";
|
||||
|
||||
import {Controlled as CodeMirror} from "react-codemirror2";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
@@ -543,7 +544,7 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if(accountItem.name === "WebAuthn credentials") {
|
||||
} else if (accountItem.name === "WebAuthn credentials") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
@@ -554,6 +555,22 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "Managed accounts") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("user:Managed accounts"), i18next.t("user:Managed accounts"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<ManagedAccountTable
|
||||
title={i18next.t("user:Managed accounts")}
|
||||
table={this.state.user.managedAccounts ?? []}
|
||||
onUpdateTable={(table) => {this.updateUserField("managedAccounts", table);}}
|
||||
applications={this.state.applications}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -504,7 +504,13 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
|
||||
renderSignedInBox() {
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
const silentSignin = params.get("silentSignin");
|
||||
if (this.props.account === undefined || this.props.account === null) {
|
||||
if (window !== window.parent) {
|
||||
const message = {tag: "Casdoor", type: "SilentSignin", data: "user-not-logged-in"};
|
||||
window.parent.postMessage(message, "*");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const application = this.getApplicationObj();
|
||||
@@ -512,8 +518,6 @@ class LoginPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
const silentSignin = params.get("silentSignin");
|
||||
if (silentSignin !== null) {
|
||||
if (window !== window.parent) {
|
||||
const message = {tag: "Casdoor", type: "SilentSignin", data: "signing-in"};
|
||||
|
@@ -21,6 +21,7 @@ import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import AffiliationSelect from "../common/AffiliationSelect";
|
||||
import OAuthWidget from "../common/OAuthWidget";
|
||||
import SelectRegionBox from "../SelectRegionBox";
|
||||
|
||||
class PromptPage extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -90,6 +91,16 @@ class PromptPage extends React.Component {
|
||||
this.submitUserEdit(false);
|
||||
}
|
||||
|
||||
updateUserFieldWithoutSubmit(key, value) {
|
||||
value = this.parseUserField(key, value);
|
||||
|
||||
const user = this.state.user;
|
||||
user[key] = value;
|
||||
this.setState({
|
||||
user: user,
|
||||
});
|
||||
}
|
||||
|
||||
renderAffiliation(application) {
|
||||
if (!Setting.isAffiliationPrompted(application)) {
|
||||
return null;
|
||||
@@ -120,6 +131,31 @@ class PromptPage extends React.Component {
|
||||
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();}} />)
|
||||
)
|
||||
}
|
||||
{
|
||||
(application === null || this.state.user === null) ? null : (
|
||||
application?.signupItems.filter(signupItem => Setting.isSignupItemPrompted(signupItem)).map((signupItem, index) => {
|
||||
if (signupItem.name !== "Country/Region") {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Row key={signupItem.name} style={{marginTop: "20px", justifyContent: "space-between"}} >
|
||||
<Col style={{marginTop: "5px"}} >
|
||||
<span style={{marginLeft: "5px"}}>
|
||||
{
|
||||
i18next.t("user:Country/Region")
|
||||
}:
|
||||
</span>
|
||||
</Col>
|
||||
<Col >
|
||||
<SelectRegionBox defaultValue={this.state.user.region} onChange={(value) => {
|
||||
this.updateUserFieldWithoutSubmit("region", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
})
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -151,7 +187,7 @@ class PromptPage extends React.Component {
|
||||
if (redirectUrl === "") {
|
||||
redirectUrl = res.data2;
|
||||
}
|
||||
if (redirectUrl !== "") {
|
||||
if (redirectUrl !== "" && redirectUrl !== null) {
|
||||
Setting.goToLink(redirectUrl);
|
||||
} else {
|
||||
Setting.goToLogin(this, this.getApplicationObj());
|
||||
|
@@ -27,15 +27,23 @@ class SingleCard extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
wrappedAsSilentSigninLink(link) {
|
||||
if (link.startsWith("http")) {
|
||||
link += link.includes("?") ? "&silentSignin=1" : "?silentSignin=1";
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
renderCardMobile(logo, link, title, desc, time, isSingle) {
|
||||
const gridStyle = {
|
||||
width: "100vw",
|
||||
textAlign: "center",
|
||||
cursor: "pointer",
|
||||
};
|
||||
const silentSigninLink = this.wrappedAsSilentSigninLink(link);
|
||||
|
||||
return (
|
||||
<Card.Grid style={gridStyle} onClick={() => Setting.goToLinkSoft(this, link)}>
|
||||
<Card.Grid style={gridStyle} onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}>
|
||||
<img src={logo} alt="logo" height={60} style={{marginBottom: "20px"}} />
|
||||
<Meta
|
||||
title={title}
|
||||
@@ -46,6 +54,8 @@ class SingleCard extends React.Component {
|
||||
}
|
||||
|
||||
renderCard(logo, link, title, desc, time, isSingle) {
|
||||
const silentSigninLink = this.wrappedAsSilentSigninLink(link);
|
||||
|
||||
return (
|
||||
<Col style={{paddingLeft: "20px", paddingRight: "20px", paddingBottom: "20px", marginBottom: "20px"}} span={6}>
|
||||
<Card
|
||||
@@ -53,7 +63,7 @@ class SingleCard extends React.Component {
|
||||
cover={
|
||||
<img alt="logo" src={logo} style={{width: "100%", height: "210px", objectFit: "scale-down"}} />
|
||||
}
|
||||
onClick={() => Setting.goToLinkSoft(this, link)}
|
||||
onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}
|
||||
style={isSingle ? {width: "320px"} : {width: "100%"}}
|
||||
>
|
||||
<Meta title={title} description={desc} />
|
||||
|
@@ -13,7 +13,7 @@ code {
|
||||
}
|
||||
|
||||
.logo {
|
||||
background: url("https://cdn.casdoor.com/logo/casdoor-logo_1185x256.png");
|
||||
background: url("https://cdn.casbin.org/img/casdoor-logo_1185x256.png");
|
||||
background-size: 130px, 27px;
|
||||
width: 130px;
|
||||
height: 27px;
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "Aktionen",
|
||||
"Actions - Tooltip": "Aktionen - Tooltip",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "Berechtigung bearbeiten",
|
||||
"Effect": "Effekt",
|
||||
"Effect - Tooltip": "Effekt - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "Ressourcentyp",
|
||||
"Resource type - Tooltip": "Ressourcentyp - Tooltip",
|
||||
"Resources": "Ressourcen",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "Primärschlüssel der Tabelle - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "Link",
|
||||
"Location": "Standort",
|
||||
"Location - Tooltip": "Standort - Tooltip",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "Passwort ändern...",
|
||||
"New Email": "Neue E-Mail",
|
||||
"New Password": "Neues Passwort",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Info-bulle",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "Autorisation d'édition",
|
||||
"Effect": "Effet",
|
||||
"Effect - Tooltip": "Effet - Infobulle",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "Type de ressource",
|
||||
"Resource type - Tooltip": "Type de ressource - infobulle",
|
||||
"Resources": "Ressource",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "Clé primaire du tableau - infobulle"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "Lier",
|
||||
"Location": "Localisation",
|
||||
"Location - Tooltip": "Localisation - Infobulle",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "Modifier le mot de passe...",
|
||||
"New Email": "Nouvel e-mail",
|
||||
"New Password": "Nouveau mot de passe",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "アクション",
|
||||
"Actions - Tooltip": "アクション → ツールチップ",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "権限を編集",
|
||||
"Effect": "効果",
|
||||
"Effect - Tooltip": "エフェクト - ツールチップ",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "リソースタイプ",
|
||||
"Resource type - Tooltip": "リソースタイプ - ツールチップ",
|
||||
"Resources": "リソース",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "テーブルのプライマリキー - ツールチップ"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "リンク",
|
||||
"Location": "場所",
|
||||
"Location - Tooltip": "場所 → ツールチップ",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "パスワードを変更...",
|
||||
"New Email": "新しいメール",
|
||||
"New Password": "新しいパスワード",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "Действия",
|
||||
"Actions - Tooltip": "Действия - Подсказка",
|
||||
"Admin": "Admin",
|
||||
"Allow": "Allow",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approved": "Approved",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Deny": "Deny",
|
||||
"Edit Permission": "Изменить права доступа",
|
||||
"Effect": "Эффект",
|
||||
"Effect - Tooltip": "Эффект - Подсказка",
|
||||
"New Permission": "New Permission",
|
||||
"Pending": "Pending",
|
||||
"Read": "Read",
|
||||
"Resource type": "Тип ресурса",
|
||||
"Resource type - Tooltip": "Тип ресурса - Подсказка",
|
||||
"Resources": "Ресурсы",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
"Submitter - Tooltip": "Submitter - Tooltip",
|
||||
"TreeNode": "TreeNode",
|
||||
"Write": "Write"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "Основная таблица - Подсказка"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "About Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"Community": "Community",
|
||||
"Get CPU Usage Failed": "Get CPU Usage Failed",
|
||||
"Get Memory Usage Failed": "Get Memory Usage Failed",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Unknown Version": "Unknown Version",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "Ссылка",
|
||||
"Location": "Местоположение",
|
||||
"Location - Tooltip": "Расположение - Подсказка",
|
||||
"Managed accounts": "Managed accounts",
|
||||
"Modify password...": "Изменить пароль...",
|
||||
"New Email": "Новое письмо",
|
||||
"New Password": "Новый пароль",
|
||||
|
@@ -346,14 +346,20 @@
|
||||
"permission": {
|
||||
"Actions": "动作",
|
||||
"Actions - Tooltip": "授权的动作",
|
||||
"Admin": "管理员权限",
|
||||
"Allow": "允许",
|
||||
"Approve time": "审批时间",
|
||||
"Approve time - Tooltip": "该授权被审批通过的时间",
|
||||
"Approved": "审批通过",
|
||||
"Approver": "审批者",
|
||||
"Approver - Tooltip": "审批通过该授权的人",
|
||||
"Deny": "拒绝",
|
||||
"Edit Permission": "编辑权限",
|
||||
"Effect": "效果",
|
||||
"Effect - Tooltip": "允许还是拒绝",
|
||||
"New Permission": "添加权限",
|
||||
"Pending": "待审批",
|
||||
"Read": "读权限",
|
||||
"Resource type": "资源类型",
|
||||
"Resource type - Tooltip": "授权资源的类型",
|
||||
"Resources": "资源",
|
||||
@@ -361,7 +367,9 @@
|
||||
"State": "审批状态",
|
||||
"State - Tooltip": "该授权现在的状态",
|
||||
"Submitter": "申请者",
|
||||
"Submitter - Tooltip": "申请该授权的人"
|
||||
"Submitter - Tooltip": "申请该授权的人",
|
||||
"TreeNode": "树节点",
|
||||
"Write": "写权限"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "支付宝",
|
||||
@@ -595,11 +603,15 @@
|
||||
"Table primary key - Tooltip": "表主键,如id"
|
||||
},
|
||||
"system": {
|
||||
"About Casdoor": "关于 Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "一个支持 OAuth 2.0、OIDC、SAML 和 CAS 的 Web UI 的身份和访问管理 (IAM)/单点登录 (SSO) 平台",
|
||||
"CPU Usage": "CPU Usage",
|
||||
"CPU Usage": "CPU使用率",
|
||||
"Community": "社区",
|
||||
"Get CPU Usage Failed": "获取CPU使用率失败",
|
||||
"Get Memory Usage Failed": "获取内存使用率失败",
|
||||
"Memory Usage": "内存使用率",
|
||||
"Official Website": "官方网站",
|
||||
"Unknown Version": "未知版本",
|
||||
"Version": "版本"
|
||||
},
|
||||
"token": {
|
||||
@@ -645,6 +657,7 @@
|
||||
"Link": "绑定",
|
||||
"Location": "城市",
|
||||
"Location - Tooltip": "居住地址所在的城市",
|
||||
"Managed accounts": "托管账户",
|
||||
"Modify password...": "编辑密码...",
|
||||
"New Email": "新邮箱",
|
||||
"New Password": "新密码",
|
||||
|
Reference in New Issue
Block a user