Permission stuff

This commit is contained in:
2020-06-27 22:47:12 +02:00
parent be6d48ac10
commit e48ea51a5a
19 changed files with 493 additions and 254 deletions

View File

@@ -104,6 +104,14 @@ export default class API {
}
async sendTestMail(receiver) {
return this.apiCall("sendTestMail", { receiver: receiver });
return this.apiCall("mail/test", { receiver: receiver });
}
async fetchPermissions() {
return this.apiCall("permission/fetch");
}
async savePermissions(permissions) {
return this.apiCall("permission/save", { permissions: permissions });
}
};

View File

@@ -209,8 +209,26 @@ export default class Overview extends React.Component {
<li><b>Load Average</b>: { loadAvg }</li>
<li><b>Database</b>: { this.state.server["database"] }</li>
<li><b>Mail</b>: { this.state.server["mail"] === true
? <span>OK<Icon icon={""} className={"ml-2"}/></span>
: <Link to={"/admin/settings"}>Not configured</Link>}</li>
? <span>
OK
<Icon icon={"check-circle"} className={"ml-2 text-success"}/>
</span>
: <span>
<Link to={"/admin/settings"}>Not configured</Link>
<Icon icon={"times-circle"} className={"ml-2 text-danger"}/>
</span>}
</li>
<li>
<b>Google reCaptcha</b>: { this.state.server["reCaptcha"] === true
? <span>
OK
<Icon icon={"check-circle"} className={"ml-2 text-success"}/>
</span>
: <span>
<Link to={"/admin/settings"}>Not configured</Link>
<Icon icon={"times-circle"} className={"ml-2 text-danger"}/>
</span>}
</li>
</ul>
</div>
</Collapse>

View File

@@ -1,6 +1,8 @@
import * as React from "react";
import {Link} from "react-router-dom";
import Icon from "../elements/icon";
import Alert from "../elements/alert";
import ReactTooltip from "react-tooltip";
export default class PermissionSettings extends React.Component {
@@ -10,11 +12,127 @@ export default class PermissionSettings extends React.Component {
this.state = {
alerts: [],
permissions: [],
groups: {}
groups: {},
isSaving: false,
isResetting: false
};
this.parent = {
api: props.api
}
}
componentDidMount() {
this.fetchPermissions()
}
fetchPermissions() {
this.parent.api.fetchPermissions().then((res) => {
if (!res.success) {
let alerts = this.state.alerts.slice();
alerts.push({ message: res.msg, title: "Error fetching permissions" });
this.setState({...this.state, alerts: alerts, isResetting: false});
} else {
this.setState({...this.state, groups: res.groups, permissions: res.permissions, isResetting: false});
}
});
}
removeAlert(i) {
if (i >= 0 && i < this.state.alerts.length) {
let alerts = this.state.alerts.slice();
alerts.splice(i, 1);
this.setState({...this.state, alerts: alerts});
}
}
onChangeMethod(e, index) {
if (index < 0 || index >= this.state.permissions.length) {
return;
}
let value = e.target.value;
let newPermissions = this.state.permissions.slice();
newPermissions[index].method = value;
this.setState({ ...this.state, permissions: newPermissions })
}
render() {
let alerts = [];
for (let i = 0; i < this.state.alerts.length; i++) {
alerts.push(<Alert key={"error-" + i} onClose={() => this.removeAlert(i)} {...this.state.alerts[i]}/>)
}
let th = [];
th.push(<th key={"th-method"}>Method</th>);
th.push(<th key={"th-everyone"} className={"text-center"}>Everyone</th>);
for (let groupId in this.state.groups) {
if (this.state.groups.hasOwnProperty(groupId)) {
let groupName = this.state.groups[groupId].name;
let groupColor = this.state.groups[groupId].color;
th.push(
<th key={"th-" + groupId} className={"text-center"}>
<span key={"group-" + groupId} className={"badge text-white"} style={{backgroundColor: groupColor}}>
{groupName}
</span>
</th>
);
}
}
let tr = [];
for (let i = 0; i < this.state.permissions.length; i++) {
let permission = this.state.permissions[i];
let td = [];
if (permission.description) {
td.push(
<td>
<ReactTooltip id={"tooltip-" + i} />
{ permission.method }
<Icon icon={"info-circle"} className={"text-info float-right"}
data-tip={permission.description} data-place={"right"} data-type={"info"}
data-effect={"solid"} data-for={"tooltip-" + i} />
</td>
);
} else {
td.push(
<td>
<ReactTooltip id={"tooltip-" + i} />
<input type={"text"} maxLength={32} value={this.state.permissions[i].method}
onChange={(e) => this.onChangeMethod(e, i)} />
<Icon icon={"trash"} className={"text-danger float-right"}
data-tip={"Delete"} data-place={"right"} data-type={"error"}
data-effect={"solid"} data-for={"tooltip-" + i}
onClick={() => this.onDeletePermission(i)} style={{cursor: "pointer"}} />
</td>
);
}
td.push(
<td key={"td-everyone"} className={"text-center"}>
<input type={"checkbox"} checked={this.state.permissions[i].groups.length === 0}
onChange={(e) => this.onChangePermission(e, i)}/>
</td>
);
for (let groupId in this.state.groups) {
if (this.state.groups.hasOwnProperty(groupId)) {
groupId = parseInt(groupId);
td.push(
<td key={"td-" + groupId} className={"text-center"}>
<input type={"checkbox"} checked={this.state.permissions[i].groups.includes(groupId)}
onChange={(e) => this.onChangePermission(e, i, groupId)}/>
</td>
);
}
}
tr.push(<tr key={"permission-" + i}>{td}</tr>);
}
return <>
<div className="content-header">
<div className="container-fluid">
@@ -35,15 +153,110 @@ export default class PermissionSettings extends React.Component {
<div className={"content"}>
<div className={"row"}>
<div className={"col-lg-6 pl-5 pr-5"}>
<form>
<Link to={"/admin/users"} className={"btn btn-info mt-2 mr-2"}>
<Icon icon={"arrow-left"}/>
&nbsp;Back
</Link>
{alerts}
<form onSubmit={(e) => e.preventDefault()}>
<table className={"table table-bordered table-hover dataTable dtr-inline"}>
<thead>
<tr role={"row"}>
{th}
</tr>
</thead>
<tbody>
{tr}
</tbody>
</table>
<div className={"mt-2"}>
<Link to={"/admin/users"} className={"btn btn-primary"}>
<Icon icon={"arrow-left"}/>
&nbsp;Back
</Link>
<button className={"btn btn-info ml-2"} onClick={() => this.onAddPermission()} disabled={this.state.isResetting || this.state.isSaving}>
<Icon icon={"plus"}/>&nbsp;Add new Permission
</button>
<button className={"btn btn-secondary ml-2"} onClick={() => this.onResetPermissions()} disabled={this.state.isResetting || this.state.isSaving}>
{ this.state.isResetting ? <span>Resetting&nbsp;<Icon icon={"circle-notch"}/></span> : "Reset" }
</button>
<button className={"btn btn-success ml-2"} onClick={() => this.onSavePermissions()} disabled={this.state.isResetting || this.state.isSaving}>
{ this.state.isSaving ? <span>Saving&nbsp;<Icon icon={"circle-notch"}/></span> : "Save" }
</button>
</div>
</form>
</div>
</div>
</div>
</>;
}
onAddPermission() {
let newPermissions = this.state.permissions.slice();
newPermissions.push({ method: "", groups: [], description: null });
this.setState({ ...this.state, permissions: newPermissions })
}
onResetPermissions() {
this.setState({ ...this.state, isResetting: true });
this.fetchPermissions();
}
onSavePermissions() {
this.setState({ ...this.state, isSaving: true });
let permissions = [];
for (let i = 0; i < this.state.permissions.length; i++) {
let permission = this.state.permissions[i];
permissions.push({ method: permission.method, groups: permission.groups });
}
this.parent.api.savePermissions(permissions).then((res) => {
if (!res.success) {
let alerts = this.state.alerts.slice();
alerts.push({ message: res.msg, title: "Error saving permissions" });
this.setState({...this.state, alerts: alerts, isSaving: false});
} else {
this.setState({...this.state, isSaving: false});
}
});
}
onDeletePermission(index) {
if (index < 0 || index >= this.state.permissions.length) {
return;
}
let newPermissions = this.state.permissions.slice();
newPermissions.splice(index, 1);
this.setState({ ...this.state, permissions: newPermissions })
}
onChangePermission(event, index, group = null) {
if (index < 0 || index >= this.state.permissions.length) {
return;
}
let isChecked = event.target.checked;
let newPermissions = this.state.permissions.slice();
if (group === null) {
if (isChecked) {
newPermissions[index].groups = [];
} else {
return;
}
} else {
if (isChecked && !newPermissions[index].groups.includes(group)) {
newPermissions[index].groups.push(group);
} else if(!isChecked) {
let indexOf = newPermissions[index].groups.indexOf(group);
if (indexOf !== -1) {
newPermissions[index].groups.splice(indexOf, 1);
} else {
return;
}
} else {
return;
}
}
this.setState({ ...this.state, permissions: newPermissions })
}
};

View File

@@ -78,6 +78,7 @@ export default class Settings extends React.Component {
return this.state.general.keys.includes(key)
|| this.state.mail.keys.includes(key)
|| this.state.messages.keys.includes(key)
|| this.state.recaptcha.keys.includes(key)
|| this.hiddenKeys.includes(key);
}