mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-31 00:30:32 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
59ff5e02ab | ||
![]() |
8d41508d6b | ||
![]() |
04f70cf012 | ||
![]() |
83724c73f9 | ||
![]() |
33e419e133 | ||
![]() |
b832c304ae | ||
![]() |
4c7f6fda37 |
@@ -203,6 +203,12 @@ func (c *ApiController) Signup() {
|
||||
}
|
||||
}
|
||||
|
||||
msg = object.CheckUsername(user.Name)
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
affected := object.AddUser(user)
|
||||
if !affected {
|
||||
c.ResponseError(fmt.Sprintf("Failed to create user, user information is invalid: %s", util.StructToJson(user)))
|
||||
|
@@ -411,6 +411,12 @@ func (c *ApiController) Login() {
|
||||
// sync info from 3rd-party if possible
|
||||
object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
||||
|
||||
msg := object.CheckUsername(user.Name)
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
affected := object.AddUser(user)
|
||||
if !affected {
|
||||
c.ResponseError(fmt.Sprintf("Failed to create user, user information is invalid: %s", util.StructToJson(user)))
|
||||
|
@@ -158,6 +158,12 @@ func (c *ApiController) UpdateUser() {
|
||||
columns = strings.Split(columnsStr, ",")
|
||||
}
|
||||
|
||||
msg := object.CheckUsername(user.Name)
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
isGlobalAdmin := c.IsGlobalAdmin()
|
||||
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
||||
if affected {
|
||||
@@ -183,6 +189,12 @@ func (c *ApiController) AddUser() {
|
||||
return
|
||||
}
|
||||
|
||||
msg := object.CheckUsername(user.Name)
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -313,3 +313,19 @@ func CheckAccessPermission(userId string, application *Application) (bool, error
|
||||
}
|
||||
return allowed, err
|
||||
}
|
||||
|
||||
func CheckUsername(name string) string {
|
||||
if name == "" {
|
||||
return "Empty username."
|
||||
} else if len(name) > 39 {
|
||||
return "Username is too long (maximum is 39 characters)."
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
|
||||
re, _ := regexp.Compile("^[a-zA-Z0-9]+((?:-[a-zA-Z0-9]+)|(?:_[a-zA-Z0-9]+))*$")
|
||||
if !re.MatchString(name) {
|
||||
return "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."
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
@@ -409,6 +409,7 @@ func SyncLdapUsers(owner string, users []LdapRespUser, ldapId string) (*[]LdapRe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found && !AddUser(&User{
|
||||
Owner: owner,
|
||||
Name: buildLdapUserName(user.Uid, user.UidNumber),
|
||||
|
@@ -703,7 +703,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
||||
}
|
||||
// Add new user
|
||||
var name string
|
||||
if username != "" {
|
||||
if CheckUsername(username) == "" {
|
||||
name = username
|
||||
} else {
|
||||
name = fmt.Sprintf("wechat-%s", openId)
|
||||
|
@@ -63,11 +63,16 @@ func getObject(ctx *context.Context) (string, string) {
|
||||
if method == http.MethodGet {
|
||||
// query == "?id=built-in/admin"
|
||||
id := ctx.Input.Query("id")
|
||||
if id == "" {
|
||||
return "", ""
|
||||
if id != "" {
|
||||
return util.GetOwnerAndNameFromId(id)
|
||||
}
|
||||
|
||||
return util.GetOwnerAndNameFromId(id)
|
||||
owner := ctx.Input.Query("owner")
|
||||
if owner != "" {
|
||||
return owner, ""
|
||||
}
|
||||
|
||||
return "", ""
|
||||
} else {
|
||||
body := ctx.Input.RequestBody
|
||||
|
||||
|
@@ -16,8 +16,8 @@ import React, {Component} from "react";
|
||||
import "./App.less";
|
||||
import {Helmet} from "react-helmet";
|
||||
import * as Setting from "./Setting";
|
||||
import {DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
|
||||
import {Avatar, BackTop, Button, Card, Dropdown, Layout, Menu, Result} from "antd";
|
||||
import {BarsOutlined, DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
|
||||
import {Avatar, BackTop, Button, Card, Drawer, Dropdown, Layout, Menu, Result} from "antd";
|
||||
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
||||
import OrganizationListPage from "./OrganizationListPage";
|
||||
import OrganizationEditPage from "./OrganizationEditPage";
|
||||
@@ -85,6 +85,7 @@ class App extends Component {
|
||||
selectedMenuKey: 0,
|
||||
account: undefined,
|
||||
uri: null,
|
||||
menuVisible: false,
|
||||
};
|
||||
|
||||
Setting.initServerUrl();
|
||||
@@ -298,12 +299,12 @@ class App extends Component {
|
||||
<Menu onClick={this.handleRightDropdownClick.bind(this)}>
|
||||
<Menu.Item key="/account">
|
||||
<SettingOutlined />
|
||||
|
||||
|
||||
{i18next.t("account:My Account")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="/logout">
|
||||
<LogoutOutlined />
|
||||
|
||||
|
||||
{i18next.t("account:Logout")}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
@@ -388,9 +389,6 @@ class App extends Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
if (Setting.isAdminUser(this.state.account)) {
|
||||
res.push(
|
||||
<Menu.Item key="/roles">
|
||||
<Link to="/roles">
|
||||
@@ -598,6 +596,18 @@ class App extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
onClose = () => {
|
||||
this.setState({
|
||||
menuVisible: false,
|
||||
});
|
||||
};
|
||||
|
||||
showMenu = () => {
|
||||
this.setState({
|
||||
menuVisible: true,
|
||||
});
|
||||
};
|
||||
|
||||
renderContent() {
|
||||
if (!Setting.isMobile()) {
|
||||
return (
|
||||
@@ -616,7 +626,7 @@ class App extends Component {
|
||||
// theme="dark"
|
||||
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
||||
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
||||
style={{lineHeight: "64px", width: "78%", position: "absolute", left: "145px"}}
|
||||
style={{lineHeight: "64px", position: "absolute", left: "145px", right: "200px"}}
|
||||
>
|
||||
{
|
||||
this.renderMenu()
|
||||
@@ -649,22 +659,28 @@ class App extends Component {
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
<Menu
|
||||
// theme="dark"
|
||||
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
|
||||
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
||||
style={{lineHeight: "64px"}}
|
||||
>
|
||||
{
|
||||
this.renderMenu()
|
||||
}
|
||||
<div style = {{float: "right"}}>
|
||||
<Drawer title={i18next.t("general:Close")} placement="left" visible={this.state.menuVisible} onClose={this.onClose}>
|
||||
<Menu
|
||||
// theme="dark"
|
||||
mode={(Setting.isMobile()) ? "inline" : "horizontal"}
|
||||
selectedKeys={[`${this.state.selectedMenuKey}`]}
|
||||
style={{lineHeight: "64px"}}
|
||||
onClick={this.onClose}
|
||||
>
|
||||
{
|
||||
this.renderAccount()
|
||||
this.renderMenu()
|
||||
}
|
||||
<SelectLanguageBox />
|
||||
</div>
|
||||
</Menu>
|
||||
</Menu>
|
||||
</Drawer>
|
||||
<Button icon={<BarsOutlined />} onClick={this.showMenu} type="text">
|
||||
{i18next.t("general:Menu")}
|
||||
</Button>
|
||||
<div style = {{float: "right"}}>
|
||||
{
|
||||
this.renderAccount()
|
||||
}
|
||||
<SelectLanguageBox />
|
||||
</div>
|
||||
</Header>
|
||||
{
|
||||
this.renderRouter()
|
||||
|
@@ -341,7 +341,7 @@ class PermissionListPage extends BaseListPage {
|
||||
this.setState({loading: true});
|
||||
|
||||
const getPermissions = Setting.isLocalAdminUser(this.props.account) ? PermissionBackend.getPermissions : PermissionBackend.getPermissionsBySubmitter;
|
||||
getPermissions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
getPermissions(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
|
@@ -25,7 +25,7 @@ class RoleListPage extends BaseListPage {
|
||||
newRole() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "built-in",
|
||||
owner: this.props.account.owner,
|
||||
name: `role_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Role - ${randomName}`,
|
||||
@@ -211,7 +211,7 @@ class RoleListPage extends BaseListPage {
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({loading: true});
|
||||
RoleBackend.getRoles("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
RoleBackend.getRoles(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
|
@@ -661,7 +661,7 @@ class UserEditPage extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.loading ? <Spin size="large" /> : (
|
||||
this.state.loading ? <Spin size="large" style={{marginLeft: "50%", marginTop: "10%"}} /> : (
|
||||
this.state.user !== null ? this.renderUser() :
|
||||
<Result
|
||||
status="404"
|
||||
|
@@ -44,10 +44,11 @@ class SingleCard extends React.Component {
|
||||
|
||||
return (
|
||||
<Card.Grid style={gridStyle} onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}>
|
||||
<img src={logo} alt="logo" height={60} style={{marginBottom: "20px"}} />
|
||||
<img src={logo} alt="logo" width={"100%"} style={{marginBottom: "20px"}} />
|
||||
<Meta
|
||||
title={title}
|
||||
description={desc}
|
||||
style={{justifyContent: "center"}}
|
||||
/>
|
||||
</Card.Grid>
|
||||
);
|
||||
@@ -61,7 +62,7 @@ class SingleCard extends React.Component {
|
||||
<Card
|
||||
hoverable
|
||||
cover={
|
||||
<img alt="logo" src={logo} style={{width: "100%", height: "210px", objectFit: "scale-down"}} />
|
||||
<img alt="logo" src={logo} style={{width: "100%", objectFit: "scale-down"}} />
|
||||
}
|
||||
onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}
|
||||
style={isSingle ? {width: "320px"} : {width: "100%"}}
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Certs",
|
||||
"Click to Upload": "Click to Upload",
|
||||
"Client IP": "Client-IP",
|
||||
"Close": "Close",
|
||||
"Created time": "Erstellte Zeit",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master-Passwort",
|
||||
"Master password - Tooltip": "Masterpasswort - Tooltip",
|
||||
"Menu": "Menu",
|
||||
"Method": "Methode",
|
||||
"Model": "Model",
|
||||
"Model - Tooltip": "Model - Tooltip",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Certs",
|
||||
"Click to Upload": "Click to Upload",
|
||||
"Client IP": "Client IP",
|
||||
"Close": "Close",
|
||||
"Created time": "Created time",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "Logo - Tooltip",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Menu": "Menu",
|
||||
"Method": "Method",
|
||||
"Model": "Model",
|
||||
"Model - Tooltip": "Model - Tooltip",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Certes",
|
||||
"Click to Upload": "Click to Upload",
|
||||
"Client IP": "IP du client",
|
||||
"Close": "Close",
|
||||
"Created time": "Date de création",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Mot de passe maître",
|
||||
"Master password - Tooltip": "Mot de passe maître - Infobulle",
|
||||
"Menu": "Menu",
|
||||
"Method": "Méthode",
|
||||
"Model": "Model",
|
||||
"Model - Tooltip": "Model - Tooltip",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Certs",
|
||||
"Click to Upload": "Click to Upload",
|
||||
"Client IP": "クライアント IP",
|
||||
"Close": "Close",
|
||||
"Created time": "作成日時",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "マスターパスワード",
|
||||
"Master password - Tooltip": "マスターパスワード - ツールチップ",
|
||||
"Menu": "Menu",
|
||||
"Method": "方法",
|
||||
"Model": "Model",
|
||||
"Model - Tooltip": "Model - Tooltip",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Certs",
|
||||
"Click to Upload": "Click to Upload",
|
||||
"Client IP": "Client IP",
|
||||
"Close": "Close",
|
||||
"Created time": "Created time",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Menu": "Menu",
|
||||
"Method": "Method",
|
||||
"Model": "Model",
|
||||
"Model - Tooltip": "Model - Tooltip",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "Сертификаты",
|
||||
"Click to Upload": "Нажмите здесь, чтобы загрузить",
|
||||
"Client IP": "IP клиента",
|
||||
"Close": "Close",
|
||||
"Created time": "Время создания",
|
||||
"Default application": "Default application",
|
||||
"Default application - Tooltip": "Default application - Tooltip",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Мастер-пароль",
|
||||
"Master password - Tooltip": "Мастер-пароль - Tooltip",
|
||||
"Menu": "Menu",
|
||||
"Method": "Метод",
|
||||
"Model": "Модель",
|
||||
"Model - Tooltip": "Модель - Подсказка",
|
||||
|
@@ -133,6 +133,7 @@
|
||||
"Certs": "证书",
|
||||
"Click to Upload": "点击上传",
|
||||
"Client IP": "客户端IP",
|
||||
"Close": "关闭",
|
||||
"Created time": "创建时间",
|
||||
"Default application": "默认应用",
|
||||
"Default application - Tooltip": "默认应用",
|
||||
@@ -165,6 +166,7 @@
|
||||
"Logo - Tooltip": "应用程序向外展示的图标",
|
||||
"Master password": "万能密码",
|
||||
"Master password - Tooltip": "可用来登录该组织下的所有用户,方便管理员以该用户身份登录,以解决技术问题",
|
||||
"Menu": "目录",
|
||||
"Method": "方法",
|
||||
"Model": "模型",
|
||||
"Model - Tooltip": "Casbin模型",
|
||||
|
Reference in New Issue
Block a user