Compare commits

...

7 Commits

Author SHA1 Message Date
Yaodong Yu
d815bf92bd fix: handle add message in frontend (#1340) 2022-11-29 20:32:47 +08:00
WangGuan
7867060b71 feat: add quota limitation to organizations, users, providers and applications (#1339) 2022-11-29 11:01:41 +08:00
Mr Forest
8890d1d7c7 fix: check credential existence when signing via WebAuthn (#1336)
* fix: check credential existence when signing via WebAuthn

* fix review problem
2022-11-28 21:47:17 +08:00
Chell
6e6a0a074a fix: application edit mobile view (#1331)
* fix: application edit mobile view

* fix: decompose elements

* fix: decomposition

* fix: remove space component

* Update ApplicationEditPage.js

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2022-11-28 21:10:49 +08:00
Thai
cff3007992 feat: add get-permissions-by-role API (#1335) 2022-11-28 15:30:46 +08:00
Mr Forest
fe448cbcf4 feat: check user existence when signing in via verification code (#1334)
* fix:check user existence when logining by verification code

* fix review problems

* Update verification.go

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2022-11-28 00:11:33 +08:00
Chell
2ab25df950 fix: prompt page translation (#1330)
* fix: prompt page translation

* add multiple translations

* fix: translation consistency

* fix: translation consistency

* fix: add translation

* fix: add translation

* Update data.json

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2022-11-27 21:04:45 +08:00
49 changed files with 318 additions and 75 deletions

View File

@@ -21,3 +21,4 @@ isDemoMode = false
batchSize = 100
ldapServerPort = 389
languages = en,zh,es,fr,de,ja,ko,ru
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}

View File

@@ -15,6 +15,7 @@
package conf
import (
"encoding/json"
"fmt"
"os"
"runtime"
@@ -24,6 +25,15 @@ import (
"github.com/beego/beego"
)
type Quota struct {
Organization int `json:"organization"`
User int `json:"user"`
Application int `json:"application"`
Provider int `json:"provider"`
}
var quota = &Quota{-1, -1, -1, -1}
func init() {
// this array contains the beego configuration items that may be modified via env
presetConfigItems := []string{"httpport", "appname"}
@@ -35,6 +45,17 @@ func init() {
}
}
}
initQuota()
}
func initQuota() {
res := beego.AppConfig.String("quota")
if res != "" {
err := json.Unmarshal([]byte(res), quota)
if err != nil {
panic(err)
}
}
}
func GetConfigString(key string) string {
@@ -95,3 +116,7 @@ func GetConfigBatchSize() int {
}
return res
}
func GetConfigQuota() *Quota {
return quota
}

View File

@@ -93,3 +93,19 @@ func TestGetConfBool(t *testing.T) {
})
}
}
func TestGetConfigQuota(t *testing.T) {
scenarios := []struct {
description string
expected *Quota
}{
{"default", &Quota{-1, -1, -1, -1}},
}
err := beego.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
quota := GetConfigQuota()
assert.Equal(t, scenery.expected, quota)
}
}

View File

@@ -167,6 +167,12 @@ func (c *ApiController) AddApplication() {
return
}
count := object.GetApplicationCount("", "", "")
if err := checkQuotaForApplication(count); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
c.ServeJSON()
}

View File

@@ -99,6 +99,12 @@ func (c *ApiController) AddOrganization() {
return
}
count := object.GetOrganizationCount("", "", "")
if err := checkQuotaForOrganization(count); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
c.ServeJSON()
}

View File

@@ -65,6 +65,20 @@ func (c *ApiController) GetPermissionsBySubmitter() {
return
}
// GetPermissionsByRole
// @Title GetPermissionsByRole
// @Tag Permission API
// @Description get permissions by role
// @Param id query string true "The id of the role"
// @Success 200 {array} object.Permission The Response object
// @router /get-permissions-by-role [get]
func (c *ApiController) GetPermissionsByRole() {
id := c.Input().Get("id")
permissions := object.GetPermissionsByRole(id)
c.ResponseOk(permissions, len(permissions))
return
}
// GetPermission
// @Title GetPermission
// @Tag Permission API

View File

@@ -122,6 +122,12 @@ func (c *ApiController) AddProvider() {
return
}
count := object.GetProviderCount("", "", "")
if err := checkQuotaForProvider(count); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
c.ServeJSON()
}

View File

@@ -183,6 +183,12 @@ func (c *ApiController) AddUser() {
return
}
count := object.GetUserCount("", "", "")
if err := checkQuotaForUser(count); err != nil {
c.ResponseError(err.Error())
return
}
msg := object.CheckUsername(user.Name, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)

View File

@@ -153,3 +153,47 @@ func (c *ApiController) GetProviderFromContext(category string) (*object.Provide
return provider, user, true
}
func checkQuotaForApplication(count int) error {
quota := conf.GetConfigQuota().Application
if quota == -1 {
return nil
}
if count >= quota {
return fmt.Errorf("application quota is exceeded")
}
return nil
}
func checkQuotaForOrganization(count int) error {
quota := conf.GetConfigQuota().Organization
if quota == -1 {
return nil
}
if count >= quota {
return fmt.Errorf("organization quota is exceeded")
}
return nil
}
func checkQuotaForProvider(count int) error {
quota := conf.GetConfigQuota().Provider
if quota == -1 {
return nil
}
if count >= quota {
return fmt.Errorf("provider quota is exceeded")
}
return nil
}
func checkQuotaForUser(count int) error {
quota := conf.GetConfigQuota().User
if quota == -1 {
return nil
}
if count >= quota {
return fmt.Errorf("user quota is exceeded")
}
return nil
}

View File

@@ -92,6 +92,10 @@ func (c *ApiController) SendVerificationCode() {
user := c.getCurrentUser()
application := object.GetApplication(applicationId)
organization := object.GetOrganization(fmt.Sprintf("%s/%s", application.Owner, application.Organization))
if organization == nil {
c.ResponseError(c.T("OrgErr.DoNotExist"))
return
}
if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil {
c.ResponseError(c.T("LoginErr.LoginFirst"))
@@ -114,6 +118,12 @@ func (c *ApiController) SendVerificationCode() {
return
}
userByEmail := object.GetUserByEmail(organization.Name, dest)
if userByEmail == nil {
c.ResponseError(c.T("UserErr.DoNotExistSignUp"))
return
}
provider := application.GetEmailProvider()
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, dest)
case "phone":
@@ -124,8 +134,10 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(c.T("PhoneErr.NumberInvalid"))
return
}
if organization == nil {
c.ResponseError(c.T("OrgErr.DoNotExist"))
userByPhone := object.GetUserByPhone(organization.Name, dest)
if userByPhone == nil {
c.ResponseError(c.T("UserErr.DoNotExistSignUp"))
return
}

View File

@@ -104,6 +104,11 @@ func (c *ApiController) WebAuthnSigninBegin() {
c.ResponseError(fmt.Sprintf(c.T("UserErr.DoNotExistInOrg"), userOwner, userName))
return
}
if len(user.WebauthnCredentials) == 0 {
c.ResponseError(c.T("UserErr.NoWebAuthnCredential"))
return
}
options, sessionData, err := webauthnObj.BeginLogin(user)
if err != nil {
c.ResponseError(err.Error())

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
NameFormatErr = The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.
PasswordLessThanSixCharacters = Password must have at least 6 characters
InvalidInformation = Invalid information
NoWebAuthnCredential = Found no credentials for this user

View File

@@ -1,5 +1,5 @@
[ApplicationErr]
AppNotFound = 应用 %%s 未找到
AppNotFound = 应用 %s 未找到
AppNotFoundForUserID = 找不到该用户的应用程序 %s
GrantTypeNotSupport = 此应用中不支持此授权类型
HasNoProviders = 该应用无提供商
@@ -25,7 +25,7 @@ EmptyErr = 邮箱不可为空
EmailInvalid = 无效邮箱
EmailCheckResult = Email: %s
EmptyParam = 邮件参数为空: %v
InvalidReceivers = 无效的邮箱接收者: %%s
InvalidReceivers = 无效的邮箱接收者: %s
UnableGetModifyRule = 无法得到Email修改规则
[EnforcerErr]
@@ -131,6 +131,7 @@ NameFormatErr = 用户名只能包含字母数字字符、下划线或连字符
PasswordLessThanSixCharacters = 密码至少为6字符
DoNotExistSignUp = 用户不存在,请先注册
InvalidInformation = 无效信息
NoWebAuthnCredential = 该用户没有WebAuthn凭据
[StorageErr]
ObjectKeyNotAllowed = object key :%s 不被允许

View File

@@ -82,6 +82,7 @@ func initAPI() {
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
beego.Router("/api/get-permissions-by-submitter", &controllers.ApiController{}, "GET:GetPermissionsBySubmitter")
beego.Router("/api/get-permissions-by-role", &controllers.ApiController{}, "GET:GetPermissionsByRole")
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission")
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")

View File

@@ -45,9 +45,12 @@ class AdapterListPage extends BaseListPage {
const newAdapter = this.newAdapter();
AdapterBackend.addAdapter(newAdapter)
.then((res) => {
this.props.history.push({pathname: `/adapters/${newAdapter.organization}/${newAdapter.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/adapters/${newAdapter.organization}/${newAdapter.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Adapter failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Adapter failed to add: ${error}`);
});

View File

@@ -49,6 +49,9 @@ const template = `<style>
}
</style>`;
const previewGrid = Setting.isMobile() ? 22 : 11;
const previewWidth = Setting.isMobile() ? "110%" : "90%";
const sideTemplate = `<style>
.left-model{
text-align: center;
@@ -720,7 +723,7 @@ class ApplicationEditPage extends React.Component {
return (
<React.Fragment>
<Col span={11}>
<Col span={previewGrid}>
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
copy(`${window.location.origin}${signUpUrl}`);
Setting.showMessage("success", i18next.t("application:Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
@@ -729,7 +732,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: previewWidth, 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} />
@@ -740,8 +743,8 @@ class ApplicationEditPage extends React.Component {
<div style={maskStyle} />
</div>
</Col>
<Col span={11}>
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
<Col span={previewGrid}>
<Button style={{marginBottom: "10px", marginTop: Setting.isMobile() ? "15px" : "0"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
copy(`${window.location.origin}${signInUrl}`);
Setting.showMessage("success", i18next.t("application:Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
}}
@@ -749,7 +752,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: previewWidth, 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>
@@ -762,7 +765,7 @@ class ApplicationEditPage extends React.Component {
const promptUrl = `/prompt/${this.state.application.name}`;
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
return (
<Col span={11}>
<Col span={previewGrid}>
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
copy(`${window.location.origin}${promptUrl}`);
Setting.showMessage("success", i18next.t("application:Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
@@ -771,7 +774,7 @@ class ApplicationEditPage extends React.Component {
{i18next.t("application:Copy prompt page URL")}
</Button>
<br />
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", flexDirection: "column", flex: "auto"}}>
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", flexDirection: "column", flex: "auto"}}>
<PromptPage application={this.state.application} account={this.props.account} />
<div style={maskStyle} />
</div>
@@ -783,7 +786,7 @@ class ApplicationEditPage extends React.Component {
const application = Setting.deepCopy(this.state.application);
ApplicationBackend.updateApplication("admin", this.state.applicationName, application)
.then((res) => {
if (res.msg === "") {
if (res.status === "ok") {
Setting.showMessage("success", "Successfully saved");
this.setState({
applicationName: this.state.application.name,

View File

@@ -78,9 +78,12 @@ class ApplicationListPage extends BaseListPage {
const newApplication = this.newApplication();
ApplicationBackend.addApplication(newApplication)
.then((res) => {
this.props.history.push({pathname: `/applications/${newApplication.organization}/${newApplication.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/applications/${newApplication.organization}/${newApplication.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Application failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Application failed to add: ${error}`);
});

View File

@@ -43,9 +43,12 @@ class CertListPage extends BaseListPage {
const newCert = this.newCert();
CertBackend.addCert(newCert)
.then((res) => {
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Cert failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Cert failed to add: ${error}`);
});

View File

@@ -38,9 +38,12 @@ class ModelListPage extends BaseListPage {
const newModel = this.newModel();
ModelBackend.addModel(newModel)
.then((res) => {
this.props.history.push({pathname: `/models/${newModel.owner}/${newModel.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/models/${newModel.owner}/${newModel.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Model failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Model failed to add: ${error}`);
});

View File

@@ -335,7 +335,7 @@ class OrganizationEditPage extends React.Component {
const organization = Setting.deepCopy(this.state.organization);
OrganizationBackend.updateOrganization(this.state.organization.owner, this.state.organizationName, organization)
.then((res) => {
if (res.msg === "") {
if (res.status === "ok") {
Setting.showMessage("success", "Successfully saved");
this.setState({
organizationName: this.state.organization.name,

View File

@@ -75,9 +75,12 @@ class OrganizationListPage extends BaseListPage {
const newOrganization = this.newOrganization();
OrganizationBackend.addOrganization(newOrganization)
.then((res) => {
this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Organization failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Organization failed to add: ${error}`);
});

View File

@@ -51,7 +51,11 @@ class PaymentListPage extends BaseListPage {
const newPayment = this.newPayment();
PaymentBackend.addPayment(newPayment)
.then((res) => {
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
if (res.status === "ok") {
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Payment failed to add: ${res.msg}`);
}
}
)
.catch(error => {

View File

@@ -48,13 +48,12 @@ class PermissionListPage extends BaseListPage {
const newPermission = this.newPermission();
PermissionBackend.addPermission(newPermission)
.then((res) => {
if (res.msg !== "") {
Setting.showMessage("error", res.msg);
return;
if (res.status === "ok") {
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Permission failed to add: ${res.msg}`);
}
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
}
)
})
.catch(error => {
Setting.showMessage("error", `Permission failed to add: ${error}`);
});

View File

@@ -45,9 +45,12 @@ class ProductListPage extends BaseListPage {
const newProduct = this.newProduct();
ProductBackend.addProduct(newProduct)
.then((res) => {
this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Product failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Product failed to add: ${error}`);
});

View File

@@ -789,7 +789,7 @@ class ProviderEditPage extends React.Component {
const provider = Setting.deepCopy(this.state.provider);
ProviderBackend.updateProvider(this.state.owner, this.state.providerName, provider)
.then((res) => {
if (res.msg === "") {
if (res.status === "ok") {
Setting.showMessage("success", "Successfully saved");
this.setState({
owner: this.state.provider.owner,

View File

@@ -61,9 +61,12 @@ class ProviderListPage extends BaseListPage {
const newProvider = this.newProvider();
ProviderBackend.addProvider(newProvider)
.then((res) => {
this.props.history.push({pathname: `/providers/${newProvider.owner}/${newProvider.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/providers/${newProvider.owner}/${newProvider.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Provider failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Provider failed to add: ${error}`);
});

View File

@@ -40,9 +40,12 @@ class RoleListPage extends BaseListPage {
const newRole = this.newRole();
RoleBackend.addRole(newRole)
.then((res) => {
this.props.history.push({pathname: `/roles/${newRole.owner}/${newRole.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/roles/${newRole.owner}/${newRole.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Role failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Role failed to add: ${error}`);
});

View File

@@ -49,9 +49,12 @@ class SyncerListPage extends BaseListPage {
const newSyncer = this.newSyncer();
SyncerBackend.addSyncer(newSyncer)
.then((res) => {
this.props.history.push({pathname: `/syncers/${newSyncer.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/syncers/${newSyncer.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Syncer failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Syncer failed to add: ${error}`);
});

View File

@@ -42,9 +42,12 @@ class TokenListPage extends BaseListPage {
const newToken = this.newToken();
TokenBackend.addToken(newToken)
.then((res) => {
this.props.history.push({pathname: `/tokens/${newToken.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/tokens/${newToken.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Token failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Token failed to add: ${error}`);
});

View File

@@ -611,7 +611,7 @@ class UserEditPage extends React.Component {
const user = Setting.deepCopy(this.state.user);
UserBackend.updateUser(this.state.organizationName, this.state.userName, user)
.then((res) => {
if (res.msg === "") {
if (res.status === "ok") {
Setting.showMessage("success", "Successfully saved");
this.setState({
organizationName: this.state.user.owner,

View File

@@ -72,9 +72,12 @@ class UserListPage extends BaseListPage {
const newUser = this.newUser();
UserBackend.addUser(newUser)
.then((res) => {
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
} else {
Setting.showMessage("error", `User failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `User failed to add: ${error}`);
});

View File

@@ -42,9 +42,12 @@ class WebhookListPage extends BaseListPage {
const newWebhook = this.newWebhook();
WebhookBackend.addWebhook(newWebhook)
.then((res) => {
this.props.history.push({pathname: `/webhooks/${newWebhook.name}`, mode: "add"});
}
)
if (res.status === "ok") {
this.props.history.push({pathname: `/webhooks/${newWebhook.name}`, mode: "add"});
} else {
Setting.showMessage("error", `Webhook failed to add: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `Webhook failed to add: ${error}`);
});

View File

@@ -335,8 +335,8 @@ class LoginPage extends React.Component {
return (
<Result
status="error"
title="Sign Up Error"
subTitle={"The application does not allow to sign up new account"}
title={i18next.t("application:Sign Up Error")}
subTitle={i18next.t("application:The application does not allow to sign up new account")}
extra={[
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
{
@@ -368,7 +368,7 @@ class LoginPage extends React.Component {
rules={[
{
required: true,
message: "Please input your application!",
message: i18next.t("application:Please input your application!"),
},
]}
>
@@ -379,7 +379,7 @@ class LoginPage extends React.Component {
rules={[
{
required: true,
message: "Please input your organization!",
message: i18next.t("application:Please input your organization!"),
},
]}
>
@@ -681,7 +681,7 @@ class LoginPage extends React.Component {
const accessToken = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`);
} else {
Setting.showMessage("success", "Successfully logged in with webauthn credentials");
Setting.showMessage("success", i18next.t("login:Successfully logged in with webauthn credentials"));
Setting.goToLink("/");
}
} else {
@@ -689,7 +689,7 @@ class LoginPage extends React.Component {
}
})
.catch(error => {
Setting.showMessage("error", `Failed to connect to server: ${error}`);
Setting.showMessage("error", `${i18next.t("application:Failed to connect to server: ")}${error}`);
});
});
}

View File

@@ -232,8 +232,8 @@ class PromptPage extends React.Component {
return (
<Result
status="error"
title="Sign Up Error"
subTitle={"You are unexpected to see this prompt page"}
title={i18next.t("application:Sign Up Error")}
subTitle={i18next.t("application:You are unexpected to see this prompt page")}
extra={[
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
{

View File

@@ -539,8 +539,8 @@ class SignupPage extends React.Component {
return (
<Result
status="error"
title="Sign Up Error"
subTitle={"The application does not allow to sign up new account"}
title={i18next.t("application:Sign Up Error")}
subTitle={i18next.t("application:The application does not allow to sign up new account")}
extra={[
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
{

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Aktiviere Anmeldesession - Tooltip",
"Enable signup": "Anmeldung aktivieren",
"Enable signup - Tooltip": "Whether to allow users to sign up",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "Datei erfolgreich hochgeladen",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "Passwort AN",
"Password ON - Tooltip": "Whether to allow password login",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "Weiterleitungs-URL",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Anmeldesitzung",
"Signup items": "Artikel registrieren",
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "Token läuft ab",
"Token expire - Tooltip": "Token läuft ab - Tooltip",
"Token format": "Token-Format",
"Token format - Tooltip": "Token-Format - Tooltip"
"Token format - Tooltip": "Token-Format - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "Bitgröße",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Mit {type} anmelden",
"Signing in...": "Anmelden...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "Die Eingabe ist keine gültige E-Mail oder Telefon!",
"To access": "Zu Zugriff",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Enable signup - Tooltip",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "File uploaded successfully",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "Password ON",
"Password ON - Tooltip": "Password ON - Tooltip",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "Please select a HTML file",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "Redirect URL",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Signup items - Tooltip",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "Token expire",
"Token expire - Tooltip": "Token expire - Tooltip",
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
"Token format - Tooltip": "Token format - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "Bit size",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
"To access": "To access",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copiado al portapapeles con éxito",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Signin session",
"Sign Up Error": "Sign Up Error",
"Signup items": "Signup items",
"Signup items - Tooltip": "Signup items - Tooltip",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
@@ -45,6 +46,7 @@
"Token expire - Tooltip": "Expiración del Token - Tooltip",
"Token format": "Formato del Token",
"Token format - Tooltip": "Formato del Token - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page",
"Rule": "Rule",
"None": "None",
"Always": "Always"

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Activer la session de connexion - infobulle",
"Enable signup": "Activer l'inscription",
"Enable signup - Tooltip": "Whether to allow users to sign up",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "Fichier téléchargé avec succès",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "Mot de passe activé",
"Password ON - Tooltip": "Whether to allow password login",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "URL de redirection",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Connexion à la session",
"Signup items": "Inscrire des éléments",
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "Expiration du jeton",
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
"Token format": "Format du jeton",
"Token format - Tooltip": "Format du jeton - infobulle"
"Token format - Tooltip": "Format du jeton - infobulle",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "Taille du bit",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Se connecter avec {type}",
"Signing in...": "Connexion en cours...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "L'entrée n'est pas valide Email ou Téléphone !",
"To access": "Pour accéder à",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
"Enable signup": "サインアップを有効にする",
"Enable signup - Tooltip": "Whether to allow users to sign up",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "ファイルが正常にアップロードされました",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "パスワードON",
"Password ON - Tooltip": "Whether to allow password login",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "HTMLファイルを選択してください",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "リダイレクトURL",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "サインインセッション",
"Signup items": "アイテムの登録",
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "トークンの有効期限",
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
"Token format": "トークンのフォーマット",
"Token format - Tooltip": "トークンフォーマット - ツールチップ"
"Token format - Tooltip": "トークンフォーマット - ツールチップ",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "ビットサイズ",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "{type} でサインイン",
"Signing in...": "サインイン中...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "入力されたメールアドレスまたは電話番号が正しくありません。",
"To access": "アクセスするには",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to sign up",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "File uploaded successfully",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "Password ON",
"Password ON - Tooltip": "Whether to allow password login",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "Please select a HTML file",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "Redirect URL",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "Token expire",
"Token expire - Tooltip": "Token expire - Tooltip",
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
"Token format - Tooltip": "Token format - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "Bit size",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
"To access": "To access",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "Включить сеанс входа - Подсказка",
"Enable signup": "Включить регистрацию",
"Enable signup - Tooltip": "Whether to allow users to sign up",
"Failed to connect to server": "Failed to connect to server",
"File uploaded successfully": "Файл успешно загружен",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@@ -51,6 +52,8 @@
"None": "None",
"Password ON": "Пароль ВКЛ",
"Password ON - Tooltip": "Whether to allow password login",
"Please input your application!": "Please input your application!",
"Please input your organization!": "Please input your organization!",
"Please select a HTML file": "Пожалуйста, выберите HTML-файл",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Ссылка на страницу успешно скопирована в буфер обмена, пожалуйста, вставьте ее в окно инкогнито или другой браузер",
"Redirect URL": "URL перенаправления",
@@ -66,15 +69,18 @@
"Side panel HTML": "Side panel HTML",
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
"Sign Up Error": "Sign Up Error",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL страницы входа успешно скопирован в буфер обмена, пожалуйста, вставьте его в окно инкогнито или другой браузер",
"Signin session": "Сессия входа",
"Signup items": "Элементы регистрации",
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL страницы регистрации успешно скопирован в буфер обмена, пожалуйста, вставьте его в окно инкогнито или другой браузер",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
"Token expire": "Токен истекает",
"Token expire - Tooltip": "Истек токен - Подсказка",
"Token format": "Формат токена",
"Token format - Tooltip": "Формат токена - Подсказка"
"Token format - Tooltip": "Формат токена - Подсказка",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
"Bit size": "Размер бита",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Войти с помощью {type}",
"Signing in...": "Вход...",
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
"The input is not valid Email or Phone!": "Введен неверный адрес электронной почты или телефон!",
"To access": "На доступ",
"Verification Code": "Verification Code",

View File

@@ -38,6 +38,7 @@
"Enable signin session - Tooltip": "从应用登录Casdoor后Casdoor是否保持会话",
"Enable signup": "启用注册",
"Enable signup - Tooltip": "是否允许用户注册",
"Failed to connect to server": "无法连接服务器",
"File uploaded successfully": "文件上传成功",
"Form CSS": "表单CSS",
"Form CSS - Edit": "编辑表单CSS",
@@ -51,6 +52,8 @@
"None": "关闭",
"Password ON": "开启密码",
"Password ON - Tooltip": "是否允许密码登录",
"Please input your application!": "请输入你的应用",
"Please input your organization!": "请输入你的组织",
"Please select a HTML file": "请选择一个HTML文件",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "提醒页面URL已成功复制到剪贴板请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
"Redirect URL": "重定向 URL",
@@ -66,15 +69,18 @@
"Side panel HTML": "侧面板 HTML",
"Side panel HTML - Edit": "侧面板 HTML - 编辑",
"Side panel HTML - Tooltip": "侧面板 HTML - Tooltip",
"Sign Up Error": "注册错误",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "登录页面URL已成功复制到剪贴板请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
"Signin session": "保持登录会话",
"Signup items": "注册项",
"Signup items - Tooltip": "注册用户注册时需要填写的项目",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "注册页面URL已成功复制到剪贴板请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
"The application does not allow to sign up new account": "该应用不允许注册新账户",
"Token expire": "Access Token过期",
"Token expire - Tooltip": "Access Token过期时间",
"Token format": "Access Token格式",
"Token format - Tooltip": "Access Token格式"
"Token format - Tooltip": "Access Token格式",
"You are unexpected to see this prompt page": "错误跳转至提醒页面"
},
"cert": {
"Bit size": "位大小",
@@ -296,6 +302,7 @@
"Sign in with WebAuthn": "WebAuthn登录",
"Sign in with {type}": "{type}登录",
"Signing in...": "正在登录...",
"Successfully logged in with webauthn credentials": "成功使用WebAuthn证书登录",
"The input is not valid Email or Phone!": "您输入的电子邮箱格式或手机号有误!",
"To access": "访问",
"Verification Code": "验证码",