mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-03 20:50:19 +08:00
feat: add country/region select (#207)
Signed-off-by: sh1luo <690898835@qq.com>
This commit is contained in:
@ -41,6 +41,7 @@ type RequestForm struct {
|
|||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone"`
|
||||||
Affiliation string `json:"affiliation"`
|
Affiliation string `json:"affiliation"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
|
||||||
Application string `json:"application"`
|
Application string `json:"application"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
@ -149,6 +150,7 @@ func (c *ApiController) Signup() {
|
|||||||
Phone: form.Phone,
|
Phone: form.Phone,
|
||||||
Address: []string{},
|
Address: []string{},
|
||||||
Affiliation: form.Affiliation,
|
Affiliation: form.Affiliation,
|
||||||
|
Region: form.Region,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
IsGlobalAdmin: false,
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
|
@ -37,6 +37,7 @@ type User struct {
|
|||||||
Address []string `json:"address"`
|
Address []string `json:"address"`
|
||||||
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
|
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
|
||||||
Tag string `xorm:"varchar(100)" json:"tag"`
|
Tag string `xorm:"varchar(100)" json:"tag"`
|
||||||
|
Region string `xorm:"varchar(100)" json:"region"`
|
||||||
Language string `xorm:"varchar(100)" json:"language"`
|
Language string `xorm:"varchar(100)" json:"language"`
|
||||||
Score int `json:"score"`
|
Score int `json:"score"`
|
||||||
IsAdmin bool `json:"isAdmin"`
|
IsAdmin bool `json:"isAdmin"`
|
||||||
@ -145,7 +146,7 @@ func UpdateUser(id string, user *User) bool {
|
|||||||
user.UpdateUserHash()
|
user.UpdateUserHash()
|
||||||
|
|
||||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols("owner", "display_name", "avatar",
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols("owner", "display_name", "avatar",
|
||||||
"address", "language", "affiliation", "score", "tag", "is_admin", "is_global_admin", "is_forbidden",
|
"address", "region", "language", "affiliation", "score", "tag", "is_admin", "is_global_admin", "is_forbidden",
|
||||||
"hash", "properties").Update(user)
|
"hash", "properties").Update(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
61
web/src/SelectRegionBox.js
Normal file
61
web/src/SelectRegionBox.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 The casbin 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 * as Setting from "./Setting";
|
||||||
|
import { Select } from "antd";
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
class SelectRegionBox extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
value: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(e) {
|
||||||
|
this.props.onChange(e);
|
||||||
|
this.setState({value: e})
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Select virtual={false}
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
style={{width: '100%'}}
|
||||||
|
defaultValue={this.props.defaultValue || undefined}
|
||||||
|
placeholder="Please select country/region"
|
||||||
|
onChange={(value => {this.onChange(value);})}
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
option.label.indexOf(input) >= 0
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
Setting.CountryRegionData.map((item, index) => (
|
||||||
|
<Option key={index} value={item.name} label={item.name} >
|
||||||
|
<img src={`${Setting.StaticBaseUrl}/flag-icons/${item.code}.svg`} alt={item.name} height={20} />{" "}
|
||||||
|
{item.name}
|
||||||
|
</Option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectRegionBox;
|
File diff suppressed because one or more lines are too long
@ -73,6 +73,7 @@ class SignupTable extends React.Component {
|
|||||||
{id: 'ID', name: 'ID'},
|
{id: 'ID', name: 'ID'},
|
||||||
{id: 'Display name', name: 'Display name'},
|
{id: 'Display name', name: 'Display name'},
|
||||||
{id: 'Affiliation', name: 'Affiliation'},
|
{id: 'Affiliation', name: 'Affiliation'},
|
||||||
|
{id: 'Country/Region', name: 'Country/Region'},
|
||||||
{id: 'Email', name: 'Email'},
|
{id: 'Email', name: 'Email'},
|
||||||
{id: 'Password', name: 'Password'},
|
{id: 'Password', name: 'Password'},
|
||||||
{id: 'Confirm password', name: 'Confirm password'},
|
{id: 'Confirm password', name: 'Confirm password'},
|
||||||
|
@ -25,6 +25,7 @@ import PasswordModal from "./PasswordModal";
|
|||||||
import ResetModal from "./ResetModal";
|
import ResetModal from "./ResetModal";
|
||||||
import AffiliationSelect from "./common/AffiliationSelect";
|
import AffiliationSelect from "./common/AffiliationSelect";
|
||||||
import OAuthWidget from "./common/OAuthWidget";
|
import OAuthWidget from "./common/OAuthWidget";
|
||||||
|
import SelectRegionBox from "./SelectRegionBox";
|
||||||
|
|
||||||
import "codemirror/lib/codemirror.css"
|
import "codemirror/lib/codemirror.css"
|
||||||
require('codemirror/theme/material-darker.css');
|
require('codemirror/theme/material-darker.css');
|
||||||
@ -224,6 +225,16 @@ class UserEditPage extends React.Component {
|
|||||||
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} coolDownTime={60}/>) : null}
|
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} coolDownTime={60}/>) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("user:Country/Region"), i18next.t("user:Country/Region - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<SelectRegionBox defaultValue={this.state.user.region} onChange={(value) => {
|
||||||
|
this.updateUserField("region", value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
{
|
{
|
||||||
(this.state.application === null || this.state.user === null) ? null : (
|
(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)}} />
|
<AffiliationSelect labelSpan={(Setting.isMobile()) ? 22 : 2} application={this.state.application} user={this.state.user} onUpdateUserField={(key, value) => { return this.updateUserField(key, value)}} />
|
||||||
|
@ -66,6 +66,7 @@ class UserListPage extends React.Component {
|
|||||||
address: [],
|
address: [],
|
||||||
affiliation: "Example Inc.",
|
affiliation: "Example Inc.",
|
||||||
tag: "staff",
|
tag: "staff",
|
||||||
|
region: "",
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
isGlobalAdmin: false,
|
isGlobalAdmin: false,
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
@ -199,6 +200,13 @@ class UserListPage extends React.Component {
|
|||||||
width: '120px',
|
width: '120px',
|
||||||
sorter: (a, b) => a.affiliation.localeCompare(b.affiliation),
|
sorter: (a, b) => a.affiliation.localeCompare(b.affiliation),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("user:Country/Region"),
|
||||||
|
dataIndex: 'region',
|
||||||
|
key: 'region',
|
||||||
|
width: '120px',
|
||||||
|
sorter: (a, b) => a.region.localeCompare(b.region),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18next.t("user:Tag"),
|
title: i18next.t("user:Tag"),
|
||||||
dataIndex: 'tag',
|
dataIndex: 'tag',
|
||||||
|
@ -23,6 +23,7 @@ import {authConfig} from "./Auth";
|
|||||||
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||||
import * as UserBackend from "../backend/UserBackend";
|
import * as UserBackend from "../backend/UserBackend";
|
||||||
import {CountDownInput} from "../component/CountDownInput";
|
import {CountDownInput} from "../component/CountDownInput";
|
||||||
|
import SelectRegionBox from "../SelectRegionBox";
|
||||||
|
|
||||||
const formItemLayout = {
|
const formItemLayout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
@ -30,7 +31,7 @@ const formItemLayout = {
|
|||||||
span: 24,
|
span: 24,
|
||||||
},
|
},
|
||||||
sm: {
|
sm: {
|
||||||
span: 6,
|
span: 8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wrapperCol: {
|
wrapperCol: {
|
||||||
@ -69,6 +70,7 @@ class SignupPage extends React.Component {
|
|||||||
phoneCode: "",
|
phoneCode: "",
|
||||||
validEmail: false,
|
validEmail: false,
|
||||||
validPhone: false,
|
validPhone: false,
|
||||||
|
region: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
this.form = React.createRef();
|
this.form = React.createRef();
|
||||||
@ -208,6 +210,22 @@ class SignupPage extends React.Component {
|
|||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
|
} else if (signupItem.name === "Country/Region") {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
name="country_region"
|
||||||
|
key="region"
|
||||||
|
label={i18next.t("user:Country/Region")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: required,
|
||||||
|
message: i18next.t("signup:Please select your country/region!"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SelectRegionBox onChange={(value) => {this.setState({region: value})}} />
|
||||||
|
</Form.Item>
|
||||||
|
)
|
||||||
} else if (signupItem.name === "Email") {
|
} else if (signupItem.name === "Email") {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
"Please input your personal name!": "Please input your personal name!",
|
"Please input your personal name!": "Please input your personal name!",
|
||||||
"Please input your address!": "Please input your address!",
|
"Please input your address!": "Please input your address!",
|
||||||
"Please input your affiliation!": "Please input your affiliation!",
|
"Please input your affiliation!": "Please input your affiliation!",
|
||||||
|
"Please select your country/region!": "Please select your country/region!",
|
||||||
"The input is not valid Email!": "The input is not valid Email!",
|
"The input is not valid Email!": "The input is not valid Email!",
|
||||||
"Please input your Email!": "Please input your Email!",
|
"Please input your Email!": "Please input your Email!",
|
||||||
"Confirm": "Confirm",
|
"Confirm": "Confirm",
|
||||||
@ -206,6 +207,8 @@
|
|||||||
"Address - Tooltip": "Unique string-style identifier",
|
"Address - Tooltip": "Unique string-style identifier",
|
||||||
"Affiliation": "Affiliation",
|
"Affiliation": "Affiliation",
|
||||||
"Affiliation - Tooltip": "Unique string-style identifier",
|
"Affiliation - Tooltip": "Unique string-style identifier",
|
||||||
|
"Country/Region": "Country/Region",
|
||||||
|
"Country/Region - Tooltip": "Country/Region",
|
||||||
"Modify affiliation": "Modify affiliation",
|
"Modify affiliation": "Modify affiliation",
|
||||||
"Tag": "Tag",
|
"Tag": "Tag",
|
||||||
"Tag - Tooltip": "Unique string-style identifier",
|
"Tag - Tooltip": "Unique string-style identifier",
|
||||||
|
Reference in New Issue
Block a user