mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-04 05:10:19 +08:00
Add accountTable.
This commit is contained in:
@ -47,6 +47,31 @@ func initBuiltInOrganization() bool {
|
|||||||
PhonePrefix: "86",
|
PhonePrefix: "86",
|
||||||
DefaultAvatar: "https://casbin.org/img/casbin.svg",
|
DefaultAvatar: "https://casbin.org/img/casbin.svg",
|
||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
|
AccountItems: []*AccountItem{
|
||||||
|
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
|
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||||
|
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
|
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
|
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
|
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
|
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
|
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
|
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
|
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
|
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
|
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
|
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
AddOrganization(organization)
|
AddOrganization(organization)
|
||||||
return false
|
return false
|
||||||
|
@ -20,6 +20,13 @@ import (
|
|||||||
"xorm.io/core"
|
"xorm.io/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AccountItem struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Visible bool `json:"visible"`
|
||||||
|
ViewRule string `json:"viewRule"`
|
||||||
|
ModifyRule string `json:"modifyRule"`
|
||||||
|
}
|
||||||
|
|
||||||
type Organization struct {
|
type Organization struct {
|
||||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
@ -36,6 +43,8 @@ type Organization struct {
|
|||||||
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
|
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
|
||||||
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
||||||
IsProfilePublic bool `json:"isProfilePublic"`
|
IsProfilePublic bool `json:"isProfilePublic"`
|
||||||
|
|
||||||
|
AccountItems []*AccountItem `xorm:"varchar(2000)" json:"accountItems"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOrganizationCount(owner, field, value string) int {
|
func GetOrganizationCount(owner, field, value string) int {
|
||||||
|
242
web/src/AccountTable.js
Normal file
242
web/src/AccountTable.js
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
// 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 {DownOutlined, DeleteOutlined, UpOutlined} from '@ant-design/icons';
|
||||||
|
import {Button, Col, Row, Select, Switch, Table, Tooltip} from 'antd';
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
class AccountTable 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) {
|
||||||
|
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true};
|
||||||
|
if (table === undefined) {
|
||||||
|
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("provider:Name"),
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
const items = [
|
||||||
|
{name: "Organization", displayName: i18next.t("general:Organization")},
|
||||||
|
{name: "ID", displayName: i18next.t("general:ID")},
|
||||||
|
{name: "Name", displayName: i18next.t("general:Name")},
|
||||||
|
{name: "Display name", displayName: i18next.t("general:Display name")},
|
||||||
|
{name: "Avatar", displayName: i18next.t("general:Avatar")},
|
||||||
|
{name: "User type", displayName: i18next.t("general:User type")},
|
||||||
|
{name: "Password", displayName: i18next.t("general:Password")},
|
||||||
|
{name: "Email", displayName: i18next.t("general:Email")},
|
||||||
|
{name: "Phone", displayName: i18next.t("general:Phone")},
|
||||||
|
{name: "Country/Region", displayName: i18next.t("user:Country/Region")},
|
||||||
|
{name: "Location", displayName: i18next.t("user:Location")},
|
||||||
|
{name: "Affiliation", displayName: i18next.t("user:Affiliation")},
|
||||||
|
{name: "Title", displayName: i18next.t("user:Title")},
|
||||||
|
{name: "Homepage", displayName: i18next.t("user:Homepage")},
|
||||||
|
{name: "Bio", displayName: i18next.t("user:Bio")},
|
||||||
|
{name: "Tag", displayName: i18next.t("user:Tag")},
|
||||||
|
{name: "Signup application", displayName: i18next.t("general:Signup application")},
|
||||||
|
{name: "3rd-party logins", displayName: i18next.t("user:3rd-party logins")},
|
||||||
|
{name: "Properties", displayName: i18next.t("user:Properties")},
|
||||||
|
{name: "Is admin", displayName: i18next.t("user:Is admin")},
|
||||||
|
{name: "Is global admin", displayName: i18next.t("user:Is global admin")},
|
||||||
|
{name: "Is forbidden", displayName: i18next.t("user:Is forbidden")},
|
||||||
|
{name: "Is deleted", displayName: i18next.t("user:Is deleted")},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getItemDisplayName = (text) => {
|
||||||
|
const item = items.filter(item => item.name === text);
|
||||||
|
if (item.length === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return item[0].displayName;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select virtual={false} style={{width: '100%'}}
|
||||||
|
value={getItemDisplayName(text)}
|
||||||
|
onChange={value => {
|
||||||
|
this.updateField(table, index, 'name', value);
|
||||||
|
}} >
|
||||||
|
{
|
||||||
|
Setting.getDeduplicatedArray(items, table, "name").map((item, index) => <Option key={index} value={item.name}>{item.displayName}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("provider:visible"),
|
||||||
|
dataIndex: 'visible',
|
||||||
|
key: 'visible',
|
||||||
|
width: '120px',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Switch checked={text} onChange={checked => {
|
||||||
|
this.updateField(table, index, 'visible', checked);
|
||||||
|
}} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("organization:viewRule"),
|
||||||
|
dataIndex: 'viewRule',
|
||||||
|
key: 'viewRule',
|
||||||
|
width: '155px',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
if (!record.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = [
|
||||||
|
{id: 'Public', name: 'Public'},
|
||||||
|
{id: 'Self', name: 'Self'},
|
||||||
|
{id: 'Admin', name: 'Admin'},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select virtual={false} style={{width: '100%'}} value={text} onChange={(value => {
|
||||||
|
this.updateField(table, index, 'viewRule', value);
|
||||||
|
})}>
|
||||||
|
{
|
||||||
|
options.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("organization:modifyRule"),
|
||||||
|
dataIndex: 'modifyRule',
|
||||||
|
key: 'modifyRule',
|
||||||
|
width: '155px',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
if (!record.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let options;
|
||||||
|
if (record.viewRule === "Admin") {
|
||||||
|
options = [
|
||||||
|
{id: 'Admin', name: 'Admin'},
|
||||||
|
{id: 'Immutable', name: 'Immutable'},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
options = [
|
||||||
|
{id: 'Self', name: 'Self'},
|
||||||
|
{id: 'Admin', name: 'Admin'},
|
||||||
|
{id: 'Immutable', name: 'Immutable'},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select virtual={false} style={{width: '100%'}} value={text} onChange={(value => {
|
||||||
|
this.updateField(table, index, 'modifyRule', value);
|
||||||
|
})}>
|
||||||
|
{
|
||||||
|
options.map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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 AccountTable;
|
@ -20,6 +20,7 @@ import * as Setting from "./Setting";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import {LinkOutlined} from "@ant-design/icons";
|
import {LinkOutlined} from "@ant-design/icons";
|
||||||
import LdapTable from "./LdapTable";
|
import LdapTable from "./LdapTable";
|
||||||
|
import AccountTable from "./AccountTable";
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@ -250,6 +251,18 @@ class OrganizationEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("organization:Account items"), i18next.t("organization:Account items - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<AccountTable
|
||||||
|
title={i18next.t("organization:Account items")}
|
||||||
|
table={this.state.organization.accountItems}
|
||||||
|
onUpdateTable={(value) => { this.updateOrganizationField('accountItems', value)}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row style={{marginTop: '20px'}}>
|
<Row style={{marginTop: '20px'}}>
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:LDAPs"), i18next.t("general:LDAPs - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:LDAPs"), i18next.t("general:LDAPs - Tooltip"))} :
|
||||||
|
@ -40,6 +40,31 @@ class OrganizationListPage extends BaseListPage {
|
|||||||
masterPassword: "",
|
masterPassword: "",
|
||||||
enableSoftDeletion: false,
|
enableSoftDeletion: false,
|
||||||
isProfilePublic: true,
|
isProfilePublic: true,
|
||||||
|
accountItems: [
|
||||||
|
{name: "Organization", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "ID", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
||||||
|
{name: "Name", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "Display name", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Avatar", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "User type", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "Password", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||||
|
{name: "Email", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Phone", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Country/Region", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Location", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Affiliation", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Title", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Homepage", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Bio", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
|
{name: "Tag", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "Signup application", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "3rd-party logins", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||||
|
{name: "Properties", visible: false, viewRule: "Admin", modifyRule: "Admin"},
|
||||||
|
{name: "Is admin", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||||
|
{name: "Is global admin", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||||
|
{name: "Is forbidden", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||||
|
{name: "Is deleted", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ class SignupTable extends React.Component {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18next.t("provider:rule"),
|
title: i18next.t("application:rule"),
|
||||||
dataIndex: 'rule',
|
dataIndex: 'rule',
|
||||||
key: 'rule',
|
key: 'rule',
|
||||||
width: '155px',
|
width: '155px',
|
||||||
|
@ -28,10 +28,10 @@ import OAuthWidget from "./common/OAuthWidget";
|
|||||||
import SamlWidget from "./common/SamlWidget";
|
import SamlWidget from "./common/SamlWidget";
|
||||||
import SelectRegionBox from "./SelectRegionBox";
|
import SelectRegionBox from "./SelectRegionBox";
|
||||||
|
|
||||||
// import {Controlled as CodeMirror} from 'react-codemirror2';
|
import {Controlled as CodeMirror} from 'react-codemirror2';
|
||||||
// import "codemirror/lib/codemirror.css";
|
import "codemirror/lib/codemirror.css";
|
||||||
// require('codemirror/theme/material-darker.css');
|
require('codemirror/theme/material-darker.css');
|
||||||
// require("codemirror/mode/javascript/javascript");
|
require("codemirror/mode/javascript/javascript");
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@ -124,46 +124,78 @@ class UserEditPage extends React.Component {
|
|||||||
return (this.state.user.id === this.props.account?.id) || Setting.isAdminUser(this.props.account);
|
return (this.state.user.id === this.props.account?.id) || Setting.isAdminUser(this.props.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUser() {
|
renderAccountItem(accountItem) {
|
||||||
return (
|
if (!accountItem.visible) {
|
||||||
<Card size="small" title={
|
return null;
|
||||||
<div>
|
}
|
||||||
{this.state.mode === "add" ? i18next.t("user:New User") : i18next.t("user:Edit User")}
|
|
||||||
<Button onClick={() => this.submitUserEdit(false)}>{i18next.t("general:Save")}</Button>
|
const isSelf = this.state.user.id === this.props.account;
|
||||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitUserEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
const isAdmin = Setting.isAdminUser(this.props.account);
|
||||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteUser()}>{i18next.t("general:Cancel")}</Button> : null}
|
|
||||||
</div>
|
if (accountItem.viewRule === "Self") {
|
||||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
if (!isSelf && !isAdmin) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else if (accountItem.viewRule === "Admin") {
|
||||||
|
if (!isAdmin) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let disabled = false;
|
||||||
|
if (accountItem.modifyRule === "Self") {
|
||||||
|
if (!isSelf && !isAdmin) {
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
} else if (accountItem.modifyRule === "Admin") {
|
||||||
|
if (!isAdmin) {
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
} else if (accountItem.modifyRule === "Immutable") {
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountItem.name === "Organization") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '10px'}} >
|
<Row style={{marginTop: '10px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Select virtual={false} style={{width: '100%'}} disabled={!Setting.isAdminUser(this.props.account)} value={this.state.user.owner} onChange={(value => {this.updateUserField('owner', value);})}>
|
<Select virtual={false} style={{width: '100%'}} disabled={disabled} value={this.state.user.owner} onChange={(value => {this.updateUserField('owner', value);})}>
|
||||||
{
|
{
|
||||||
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "ID") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel("ID", i18next.t("general:ID - Tooltip"))} :
|
{Setting.getLabel("ID", i18next.t("general:ID - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.user.id} disabled={true} />
|
<Input value={this.state.user.id} disabled={disabled} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Name") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.user.name} disabled={!Setting.isAdminUser(this.props.account)} onChange={e => {
|
<Input value={this.state.user.name} disabled={disabled} onChange={e => {
|
||||||
this.updateUserField('name', e.target.value);
|
this.updateUserField('name', e.target.value);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Display name") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||||
@ -174,6 +206,9 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Avatar") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Avatar"), i18next.t("general:Avatar - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Avatar"), i18next.t("general:Avatar - Tooltip"))} :
|
||||||
@ -204,6 +239,9 @@ class UserEditPage extends React.Component {
|
|||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "User type") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:User type"), i18next.t("general:User type - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:User type"), i18next.t("general:User type - Tooltip"))} :
|
||||||
@ -217,44 +255,56 @@ class UserEditPage extends React.Component {
|
|||||||
</Select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Password") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<PasswordModal user={this.state.user} account={this.props.account} disabled={this.state.userName !== this.state.user.name} />
|
<PasswordModal user={this.state.user} account={this.props.account} disabled={disabled} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Email") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: '20px'}} span={11} >
|
<Col style={{paddingRight: '20px'}} span={11} >
|
||||||
<Input value={this.state.user.email}
|
<Input value={this.state.user.email}
|
||||||
disabled={this.state.user.id === this.props.account?.id ? true : !Setting.isAdminUser(this.props.account)}
|
disabled={disabled}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.updateUserField('email', e.target.value);
|
this.updateUserField('email', e.target.value);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={11} >
|
<Col span={11} >
|
||||||
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Email...")} destType={"email"} />) : null}
|
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Email...")} destType={"email"} />) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Phone") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: '20px'}} span={11} >
|
<Col style={{paddingRight: '20px'}} span={11} >
|
||||||
<Input value={this.state.user.phone} addonBefore={`+${this.state.application?.organizationObj.phonePrefix}`}
|
<Input value={this.state.user.phone} addonBefore={`+${this.state.application?.organizationObj.phonePrefix}`}
|
||||||
disabled={this.state.user.id === this.props.account?.id ? true : !Setting.isAdminUser(this.props.account)}
|
disabled={disabled}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.updateUserField('phone', e.target.value);
|
this.updateUserField('phone', e.target.value);
|
||||||
}}/>
|
}}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={11} >
|
<Col span={11} >
|
||||||
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Country/Region") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Country/Region"), i18next.t("user:Country/Region - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Country/Region"), i18next.t("user:Country/Region - Tooltip"))} :
|
||||||
@ -265,6 +315,9 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Location") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Location"), i18next.t("user:Location - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Location"), i18next.t("user:Location - Tooltip"))} :
|
||||||
@ -275,11 +328,15 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{
|
)
|
||||||
(this.state.application === null || this.state.user === null) ? null : (
|
} else if (accountItem.name === "Affiliation") {
|
||||||
<AffiliationSelect labelSpan={(Setting.isMobile()) ? 22 : 2} application={this.state.application} user={this.state.user} onUpdateUserField={(key, value) => { return this.updateUserField(key, value)}} />
|
return (
|
||||||
)
|
(this.state.application === null || this.state.user === null) ? null : (
|
||||||
}
|
<AffiliationSelect labelSpan={(Setting.isMobile()) ? 22 : 2} application={this.state.application} user={this.state.user} onUpdateUserField={(key, value) => { return this.updateUserField(key, value)}} />
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Title") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Title"), i18next.t("user:Title - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Title"), i18next.t("user:Title - Tooltip"))} :
|
||||||
@ -290,6 +347,9 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Homepage") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Homepage"), i18next.t("user:Homepage - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Homepage"), i18next.t("user:Homepage - Tooltip"))} :
|
||||||
@ -300,6 +360,9 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Bio") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Bio"), i18next.t("user:Bio - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Bio"), i18next.t("user:Bio - Tooltip"))} :
|
||||||
@ -310,6 +373,9 @@ class UserEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Tag") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("user:Tag"), i18next.t("user:Tag - Tooltip"))} :
|
{Setting.getLabel(i18next.t("user:Tag"), i18next.t("user:Tag - Tooltip"))} :
|
||||||
@ -335,102 +401,130 @@ class UserEditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Signup application") {
|
||||||
|
return (
|
||||||
<Row style={{marginTop: '20px'}} >
|
<Row style={{marginTop: '20px'}} >
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Signup application"), i18next.t("general:Signup application - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Signup application"), i18next.t("general:Signup application - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Select virtual={false} style={{width: '100%'}} disabled={!Setting.isAdminUser(this.props.account)} value={this.state.user.signupApplication} onChange={(value => {this.updateUserField('signupApplication', value);})}>
|
<Select virtual={false} style={{width: '100%'}} disabled={disabled} value={this.state.user.signupApplication} onChange={(value => {this.updateUserField('signupApplication', value);})}>
|
||||||
{
|
{
|
||||||
this.state.applications.map((application, index) => <Option key={index} value={application.name}>{application.name}</Option>)
|
this.state.applications.map((application, index) => <Option key={index} value={application.name}>{application.name}</Option>)
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{
|
)
|
||||||
!this.isSelfOrAdmin() ? null : (
|
} else if (accountItem.name === "3rd-party logins") {
|
||||||
<Row style={{marginTop: '20px'}} >
|
return (
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
!this.isSelfOrAdmin() ? null : (
|
||||||
{Setting.getLabel(i18next.t("user:3rd-party logins"), i18next.t("user:3rd-party logins - Tooltip"))} :
|
<Row style={{marginTop: '20px'}} >
|
||||||
</Col>
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
<Col span={22} >
|
{Setting.getLabel(i18next.t("user:3rd-party logins"), i18next.t("user:3rd-party logins - Tooltip"))} :
|
||||||
<div style={{marginBottom: 20}}>
|
</Col>
|
||||||
{
|
<Col span={22} >
|
||||||
(this.state.application === null || this.state.user === null) ? null : (
|
<div style={{marginBottom: 20}}>
|
||||||
this.state.application?.providers.filter(providerItem => Setting.isProviderVisible(providerItem)).map((providerItem, index) =>
|
{
|
||||||
(providerItem.provider.category === "OAuth") ? (
|
(this.state.application === null || this.state.user === null) ? null : (
|
||||||
<OAuthWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => { return this.unlinked()}} />
|
this.state.application?.providers.filter(providerItem => Setting.isProviderVisible(providerItem)).map((providerItem, index) =>
|
||||||
) : (
|
(providerItem.provider.category === "OAuth") ? (
|
||||||
<SamlWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => { return this.unlinked()}} />
|
<OAuthWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => { return this.unlinked()}} />
|
||||||
)
|
) : (
|
||||||
|
<SamlWidget key={providerItem.name} labelSpan={(Setting.isMobile()) ? 10 : 3} user={this.state.user} application={this.state.application} providerItem={providerItem} onUnlinked={() => { return this.unlinked()}} />
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
</div>
|
}
|
||||||
</Col>
|
</div>
|
||||||
</Row>
|
</Col>
|
||||||
)
|
</Row>
|
||||||
}
|
)
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Properties") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("user:Properties")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<CodeMirror
|
||||||
|
value={JSON.stringify(this.state.user.properties, null, 4)}
|
||||||
|
options={{mode: 'javascript', theme: "material-darker"}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Is admin") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("user:Is admin"), i18next.t("user:Is admin - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
|
<Switch checked={this.state.user.isAdmin} onChange={checked => {
|
||||||
|
this.updateUserField('isAdmin', checked);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Is global admin") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("user:Is global admin"), i18next.t("user:Is global admin - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
|
<Switch checked={this.state.user.isGlobalAdmin} onChange={checked => {
|
||||||
|
this.updateUserField('isGlobalAdmin', checked);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Is forbidden") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("user:Is forbidden"), i18next.t("user:Is forbidden - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
|
<Switch checked={this.state.user.isForbidden} onChange={checked => {
|
||||||
|
this.updateUserField('isForbidden', checked);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
} else if (accountItem.name === "Is deleted") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("user:Is deleted"), i18next.t("user:Is deleted - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
||||||
|
<Switch checked={this.state.user.isDeleted} onChange={checked => {
|
||||||
|
this.updateUserField('isDeleted', checked);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderUser() {
|
||||||
|
return (
|
||||||
|
<Card size="small" title={
|
||||||
|
<div>
|
||||||
|
{this.state.mode === "add" ? i18next.t("user:New User") : i18next.t("user:Edit User")}
|
||||||
|
<Button onClick={() => this.submitUserEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||||
|
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitUserEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||||
|
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteUser()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||||
|
</div>
|
||||||
|
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||||
{
|
{
|
||||||
!Setting.isAdminUser(this.props.account) ? null : (
|
this.state.application?.organizationObj.accountItems?.map(accountItem => this.renderAccountItem(accountItem))
|
||||||
<React.Fragment>
|
|
||||||
{/*<Row style={{marginTop: '20px'}} >*/}
|
|
||||||
{/* <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>*/}
|
|
||||||
{/* {i18next.t("user:Properties")}:*/}
|
|
||||||
{/* </Col>*/}
|
|
||||||
{/* <Col span={22} >*/}
|
|
||||||
{/* <CodeMirror*/}
|
|
||||||
{/* value={JSON.stringify(this.state.user.properties, null, 4)}*/}
|
|
||||||
{/* options={{mode: 'javascript', theme: "material-darker"}}*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* </Col>*/}
|
|
||||||
{/*</Row>*/}
|
|
||||||
<Row style={{marginTop: '20px'}} >
|
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("user:Is admin"), i18next.t("user:Is admin - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
|
||||||
<Switch checked={this.state.user.isAdmin} onChange={checked => {
|
|
||||||
this.updateUserField('isAdmin', checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: '20px'}} >
|
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("user:Is global admin"), i18next.t("user:Is global admin - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
|
||||||
<Switch checked={this.state.user.isGlobalAdmin} onChange={checked => {
|
|
||||||
this.updateUserField('isGlobalAdmin', checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: '20px'}} >
|
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("user:Is forbidden"), i18next.t("user:Is forbidden - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
|
||||||
<Switch checked={this.state.user.isForbidden} onChange={checked => {
|
|
||||||
this.updateUserField('isForbidden', checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: '20px'}} >
|
|
||||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("user:Is deleted"), i18next.t("user:Is deleted - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={(Setting.isMobile()) ? 22 : 2} >
|
|
||||||
<Switch checked={this.state.user.isDeleted} onChange={checked => {
|
|
||||||
this.updateUserField('isDeleted', checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Token läuft ab",
|
"Token expire": "Token läuft ab",
|
||||||
"Token expire - Tooltip": "Token läuft ab - Tooltip",
|
"Token expire - Tooltip": "Token läuft ab - Tooltip",
|
||||||
"Token format": "Token-Format",
|
"Token format": "Token-Format",
|
||||||
"Token format - Tooltip": "Token-Format - Tooltip"
|
"Token format - Tooltip": "Token-Format - Tooltip",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "Bitgröße",
|
"Bit size": "Bitgröße",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "Standard Avatar",
|
"Default avatar": "Standard Avatar",
|
||||||
"Edit Organization": "Organisation bearbeiten",
|
"Edit Organization": "Organisation bearbeiten",
|
||||||
"Favicon": "Févicon",
|
"Favicon": "Févicon",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "Website-URL",
|
"Website URL": "Website-URL",
|
||||||
"Website URL - Tooltip": "Unique string-style identifier"
|
"Website URL - Tooltip": "Unique string-style identifier",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "gefragt",
|
"prompted": "gefragt",
|
||||||
"required": "benötigt",
|
"required": "benötigt",
|
||||||
"rule": "regel",
|
|
||||||
"visible": "sichtbar"
|
"visible": "sichtbar"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Token expire",
|
"Token expire": "Token expire",
|
||||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "Bit size",
|
"Bit size": "Bit size",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
"Edit Organization": "Edit Organization",
|
"Edit Organization": "Edit Organization",
|
||||||
"Favicon": "Favicon",
|
"Favicon": "Favicon",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "Website URL",
|
"Website URL": "Website URL",
|
||||||
"Website URL - Tooltip": "Website URL - Tooltip"
|
"Website URL - Tooltip": "Website URL - Tooltip",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "prompted",
|
"prompted": "prompted",
|
||||||
"required": "required",
|
"required": "required",
|
||||||
"rule": "rule",
|
|
||||||
"visible": "visible"
|
"visible": "visible"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Expiration du jeton",
|
"Token expire": "Expiration du jeton",
|
||||||
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
|
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
|
||||||
"Token format": "Format du jeton",
|
"Token format": "Format du jeton",
|
||||||
"Token format - Tooltip": "Format du jeton - infobulle"
|
"Token format - Tooltip": "Format du jeton - infobulle",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "Taille du bit",
|
"Bit size": "Taille du bit",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "Avatar par défaut",
|
"Default avatar": "Avatar par défaut",
|
||||||
"Edit Organization": "Modifier l'organisation",
|
"Edit Organization": "Modifier l'organisation",
|
||||||
"Favicon": "Favicon",
|
"Favicon": "Favicon",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "URL du site web",
|
"Website URL": "URL du site web",
|
||||||
"Website URL - Tooltip": "Unique string-style identifier"
|
"Website URL - Tooltip": "Unique string-style identifier",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "invitée",
|
"prompted": "invitée",
|
||||||
"required": "Obligatoire",
|
"required": "Obligatoire",
|
||||||
"rule": "règle",
|
|
||||||
"visible": "Visible"
|
"visible": "Visible"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "トークンの有効期限",
|
"Token expire": "トークンの有効期限",
|
||||||
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
|
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
|
||||||
"Token format": "トークンのフォーマット",
|
"Token format": "トークンのフォーマット",
|
||||||
"Token format - Tooltip": "トークンフォーマット - ツールチップ"
|
"Token format - Tooltip": "トークンフォーマット - ツールチップ",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "ビットサイズ",
|
"Bit size": "ビットサイズ",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "デフォルトのアバター",
|
"Default avatar": "デフォルトのアバター",
|
||||||
"Edit Organization": "組織を編集",
|
"Edit Organization": "組織を編集",
|
||||||
"Favicon": "ファビコン",
|
"Favicon": "ファビコン",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "Website URL",
|
"Website URL": "Website URL",
|
||||||
"Website URL - Tooltip": "Unique string-style identifier"
|
"Website URL - Tooltip": "Unique string-style identifier",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "プロンプトされた",
|
"prompted": "プロンプトされた",
|
||||||
"required": "必須",
|
"required": "必須",
|
||||||
"rule": "ルール",
|
|
||||||
"visible": "表示"
|
"visible": "表示"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Token expire",
|
"Token expire": "Token expire",
|
||||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "Bit size",
|
"Bit size": "Bit size",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
"Edit Organization": "Edit Organization",
|
"Edit Organization": "Edit Organization",
|
||||||
"Favicon": "Favicon",
|
"Favicon": "Favicon",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "Website URL",
|
"Website URL": "Website URL",
|
||||||
"Website URL - Tooltip": "Unique string-style identifier"
|
"Website URL - Tooltip": "Unique string-style identifier",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "prompted",
|
"prompted": "prompted",
|
||||||
"required": "required",
|
"required": "required",
|
||||||
"rule": "rule",
|
|
||||||
"visible": "visible"
|
"visible": "visible"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Токен истекает",
|
"Token expire": "Токен истекает",
|
||||||
"Token expire - Tooltip": "Истек токен - Подсказка",
|
"Token expire - Tooltip": "Истек токен - Подсказка",
|
||||||
"Token format": "Формат токена",
|
"Token format": "Формат токена",
|
||||||
"Token format - Tooltip": "Формат токена - Подсказка"
|
"Token format - Tooltip": "Формат токена - Подсказка",
|
||||||
|
"rule": "rule"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "Размер бита",
|
"Bit size": "Размер бита",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "New Model"
|
"New Model": "New Model"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "Account items",
|
||||||
|
"Account items - Tooltip": "Account items - Tooltip",
|
||||||
"Default avatar": "Аватар по умолчанию",
|
"Default avatar": "Аватар по умолчанию",
|
||||||
"Edit Organization": "Изменить организацию",
|
"Edit Organization": "Изменить организацию",
|
||||||
"Favicon": "Иконка",
|
"Favicon": "Иконка",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Tags - Tooltip": "Tags - Tooltip",
|
"Tags - Tooltip": "Tags - Tooltip",
|
||||||
"Website URL": "URL сайта",
|
"Website URL": "URL сайта",
|
||||||
"Website URL - Tooltip": "Unique string-style identifier"
|
"Website URL - Tooltip": "Unique string-style identifier",
|
||||||
|
"modifyRule": "modifyRule",
|
||||||
|
"viewRule": "viewRule"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "Confirm your invoice information",
|
"Confirm your invoice information": "Confirm your invoice information",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "canUnlink",
|
"canUnlink": "canUnlink",
|
||||||
"prompted": "запрошено",
|
"prompted": "запрошено",
|
||||||
"required": "обязательный",
|
"required": "обязательный",
|
||||||
"rule": "правило",
|
|
||||||
"visible": "видимый"
|
"visible": "видимый"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"Token expire": "Access Token过期",
|
"Token expire": "Access Token过期",
|
||||||
"Token expire - Tooltip": "Access Token过期时间",
|
"Token expire - Tooltip": "Access Token过期时间",
|
||||||
"Token format": "Access Token格式",
|
"Token format": "Access Token格式",
|
||||||
"Token format - Tooltip": "Access Token格式"
|
"Token format - Tooltip": "Access Token格式",
|
||||||
|
"rule": "规则"
|
||||||
},
|
},
|
||||||
"cert": {
|
"cert": {
|
||||||
"Bit size": "位大小",
|
"Bit size": "位大小",
|
||||||
@ -259,6 +260,8 @@
|
|||||||
"New Model": "添加模型"
|
"New Model": "添加模型"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
|
"Account items": "个人页设置项",
|
||||||
|
"Account items - Tooltip": "个人设置页面中的项目",
|
||||||
"Default avatar": "默认头像",
|
"Default avatar": "默认头像",
|
||||||
"Edit Organization": "编辑组织",
|
"Edit Organization": "编辑组织",
|
||||||
"Favicon": "图标",
|
"Favicon": "图标",
|
||||||
@ -270,7 +273,9 @@
|
|||||||
"Tags": "标签集合",
|
"Tags": "标签集合",
|
||||||
"Tags - Tooltip": "可供用户选择的标签的集合",
|
"Tags - Tooltip": "可供用户选择的标签的集合",
|
||||||
"Website URL": "网页地址",
|
"Website URL": "网页地址",
|
||||||
"Website URL - Tooltip": "网页地址"
|
"Website URL - Tooltip": "网页地址",
|
||||||
|
"modifyRule": "修改规则",
|
||||||
|
"viewRule": "查看规则"
|
||||||
},
|
},
|
||||||
"payment": {
|
"payment": {
|
||||||
"Confirm your invoice information": "确认您的发票信息",
|
"Confirm your invoice information": "确认您的发票信息",
|
||||||
@ -469,7 +474,6 @@
|
|||||||
"canUnlink": "可解绑定",
|
"canUnlink": "可解绑定",
|
||||||
"prompted": "注册后提醒绑定",
|
"prompted": "注册后提醒绑定",
|
||||||
"required": "是否必填项",
|
"required": "是否必填项",
|
||||||
"rule": "规则",
|
|
||||||
"visible": "是否可见"
|
"visible": "是否可见"
|
||||||
},
|
},
|
||||||
"record": {
|
"record": {
|
||||||
|
Reference in New Issue
Block a user