web-base/fileControlPanel/src/index.js

231 lines
8.7 KiB
JavaScript
Raw Normal View History

2021-01-07 20:47:43 +01:00
import React from 'react';
import ReactDOM from 'react-dom';
2021-01-09 23:34:45 +01:00
import API from "./api";
2021-01-10 01:08:03 +01:00
import Icon from "./elements/icon";
import {FileBrowser} from "./elements/file-browser";
import {TokenList} from "./elements/token-list";
2021-01-07 20:47:43 +01:00
class FileControlPanel extends React.Component {
constructor(props) {
super(props);
this.api = new API();
this.state = {
2021-01-10 01:08:03 +01:00
loaded: false,
validatingToken: false,
errorMessage: "",
user: { },
token: { valid: false, value: "", validUntil: null, type: null },
2021-03-30 23:12:10 +02:00
files: {},
restrictions: { maxFiles: 0, maxSize: 0, extensions: "" }
2021-01-07 20:47:43 +01:00
};
}
2021-01-14 18:32:29 +01:00
onFetchFiles(files) {
this.setState({ ...this.state, files: files });
}
2021-01-14 21:45:58 +01:00
getDirectories(prefix = "/", items = null) {
let directories = { }
items = items || this.state.files;
if (prefix === "/") {
directories[0] = "/";
}
for(const fileItem of Object.values(items)) {
if (fileItem.isDirectory) {
let path = prefix + (prefix.length > 1 ? "/" : "") + fileItem.name;
directories[fileItem.uid] = path;
directories = Object.assign(directories, {...this.getDirectories(path, fileItem.items)});
}
}
return directories;
}
2021-01-14 18:32:29 +01:00
getSelectedIds(items = null, recursive = true) {
let ids = [];
items = items || this.state.files;
for (const fileItem of Object.values(items)) {
if (fileItem.selected) {
ids.push(fileItem.uid);
}
if (recursive && fileItem.isDirectory) {
ids.push(...this.getSelectedIds(fileItem.items));
}
}
return ids;
}
onSelectAll(selected, items) {
for (const fileElement of Object.values(items)) {
fileElement.selected = selected;
if (fileElement.isDirectory) {
this.onSelectAll(selected, fileElement.items);
}
}
}
onSelectFile(e, uid, items=null) {
let found = false;
let updatedFiles = (items === null) ? {...this.state.files} : items;
if (updatedFiles.hasOwnProperty(uid)) {
let fileElement = updatedFiles[uid];
found = true;
fileElement.selected = e.target.checked;
if (fileElement.isDirectory) {
this.onSelectAll(fileElement.selected, fileElement.items);
}
} else {
for (const fileElement of Object.values(updatedFiles)) {
if (fileElement.isDirectory) {
if (this.onSelectFile(e, uid, fileElement.items)) {
if (!e.target.checked) {
fileElement.selected = false;
2021-03-31 16:02:29 +02:00
}/* else if (this.getSelectedIds(fileElement.items, false).length === Object.values(fileElement.items).length) {
2021-01-14 18:32:29 +01:00
fileElement.selected = true;
2021-03-31 16:02:29 +02:00
}*/
2021-01-14 18:32:29 +01:00
found = true;
break;
}
}
}
}
if (items === null) {
this.setState({
...this.state,
files: updatedFiles
});
}
return found;
}
2021-01-12 15:49:41 +01:00
onValidateToken(token = null) {
if (token === null) {
this.setState({ ...this.state, validatingToken: true, errorMessage: "" });
token = this.state.token.value;
}
2021-01-14 21:45:58 +01:00
2021-01-12 15:49:41 +01:00
this.api.validateToken(token).then((res) => {
let newState = { ...this.state, loaded: true, validatingToken: false };
2021-01-10 01:08:03 +01:00
if (res.success) {
2021-01-12 15:49:41 +01:00
newState.token = { ...this.state.token, valid: true, validUntil: res.token.valid_until, type: res.token.type };
if (!newState.token.value) {
newState.token.value = token;
}
newState.files = res.files;
2021-03-30 23:12:10 +02:00
newState.restrictions = res.restrictions;
2021-01-10 01:08:03 +01:00
} else {
2021-01-14 23:41:16 +01:00
newState.token.value = (newState.token.value ? "" : token);
2021-01-12 15:49:41 +01:00
newState.errorMessage = res.msg;
2021-01-10 01:08:03 +01:00
}
2021-01-12 15:49:41 +01:00
this.setState(newState);
2021-01-10 01:08:03 +01:00
});
}
onUpdateToken(e) {
this.setState({ ...this.state, token: { ...this.state.token, value: e.target.value } });
}
2021-01-07 20:47:43 +01:00
render() {
2021-01-10 01:08:03 +01:00
const self = this;
const errorMessageShown = !!this.state.errorMessage;
2021-01-07 22:01:56 +01:00
2021-03-30 00:27:15 +02:00
// still loading
2021-01-09 23:34:45 +01:00
if (!this.state.loaded) {
2021-01-12 15:49:41 +01:00
let checkUser = true;
let pathName = window.location.pathname;
2021-01-14 23:41:16 +01:00
if (pathName.startsWith("/files")) {
pathName = pathName.substr("/files".length);
}
2021-01-12 15:49:41 +01:00
if (pathName.length > 1) {
let end = (pathName.endsWith("/") ? pathName.length - 2 : pathName.length - 1);
let start = (pathName.startsWith("/files/") ? ("/files/").length : 1);
let token = pathName.substr(start, end);
if (token) {
this.onValidateToken(token);
checkUser = false;
2021-01-10 01:08:03 +01:00
}
2021-01-12 15:49:41 +01:00
}
if (checkUser) {
this.api.fetchUser().then((isLoggedIn) => {
if (isLoggedIn) {
this.api.listFiles().then((res) => {
this.setState({ ...this.state, loaded: true, user: this.api.user, files: res.files });
2021-03-30 23:12:10 +02:00
this.api.getRestrictions().then((res) => {
this.setState({ ...this.state, restrictions: res.restrictions });
})
2021-01-12 15:49:41 +01:00
});
} else {
this.setState({ ...this.state, loaded: true, user: this.api.user });
}
});
}
2021-01-10 01:08:03 +01:00
return <>Loading <Icon icon={"spinner"} /></>;
2021-03-30 00:27:15 +02:00
}
// access granted
else if (this.api.loggedIn || this.state.token.valid) {
2021-01-14 18:32:29 +01:00
let selectedIds = this.getSelectedIds();
2021-01-14 21:45:58 +01:00
let directories = this.getDirectories();
2021-03-30 23:12:10 +02:00
let tokenList = (this.api.loggedIn ?
2021-01-10 01:08:03 +01:00
<div className={"row"}>
2021-01-10 23:41:00 +01:00
<div className={"col-lg-8 col-md-10 col-sm-12 mx-auto"}>
2021-01-14 21:45:58 +01:00
<TokenList api={this.api} selectedFiles={selectedIds} directories={directories} />
2021-01-10 01:08:03 +01:00
</div>
2021-03-30 23:12:10 +02:00
</div> : <></>
);
2021-01-07 22:01:56 +01:00
2021-01-13 01:36:04 +01:00
return <>
<div className={"container mt-4"}>
<div className={"row"}>
<div className={"col-lg-8 col-md-10 col-sm-12 mx-auto"}>
<h2>File Control Panel</h2>
2021-03-30 23:12:10 +02:00
<FileBrowser files={this.state.files} token={this.state.token} api={this.api}
restrictions={this.state.restrictions} directories={directories}
2021-01-14 18:32:29 +01:00
onSelectFile={this.onSelectFile.bind(this)}
onFetchFiles={this.onFetchFiles.bind(this)}/>
2021-01-13 01:36:04 +01:00
</div>
2021-01-10 01:08:03 +01:00
</div>
2021-01-13 01:36:04 +01:00
{ tokenList }
2021-01-10 01:08:03 +01:00
</div>
2021-01-13 01:36:04 +01:00
</>;
2021-01-07 22:01:56 +01:00
} else {
2021-01-10 01:08:03 +01:00
return <div className={"container mt-4"}>
<div className={"row"}>
2021-01-10 23:41:00 +01:00
<div className={"col-lg-8 col-md-10 col-sm-12 mx-auto"}>
2021-01-10 01:08:03 +01:00
<h2>File Control Panel</h2>
<form onSubmit={(e) => e.preventDefault()}>
<label htmlFor={"token"}>Enter a file token to download or upload files</label>
<input type={"text"} className={"form-control"} name={"token"} placeholder={"Enter token…"} maxLength={36}
value={this.state.token.value} onChange={(e) => self.onUpdateToken(e)}/>
2021-01-12 15:49:41 +01:00
<button className={"btn btn-success mt-2"} onClick={() => this.onValidateToken()} disabled={this.state.validatingToken}>
2021-01-10 01:08:03 +01:00
{ this.state.validatingToken ? <>Validating <Icon icon={"spinner"}/></> : "Submit" }
</button>
</form>
<div className={"alert alert-danger mt-2"} hidden={!errorMessageShown}>
{ this.state.errorMessage }
</div>
2021-03-30 00:27:15 +02:00
<div className={"mt-3"}>
Or either <a href={"/admin"}>login</a> to access the file control panel.
</div>
2021-01-10 01:08:03 +01:00
</div>
</div>
</div>;
2021-01-07 22:01:56 +01:00
}
2021-01-07 20:47:43 +01:00
}
}
ReactDOM.render(
<FileControlPanel />,
document.getElementById('root')
);