small changes
This commit is contained in:
@@ -156,8 +156,41 @@ export default class API {
|
||||
}
|
||||
|
||||
async updateProfile(username=null, fullName=null, password=null, confirmPassword = null, oldPassword = null) {
|
||||
return this.apiCall("user/updateProfile", { username: username, fullName: fullName,
|
||||
let res = await this.apiCall("user/updateProfile", { username: username, fullName: fullName,
|
||||
password: password, confirmPassword: confirmPassword, oldPassword: oldPassword });
|
||||
|
||||
if (res.success) {
|
||||
if (username !== null) {
|
||||
this.user.name = username;
|
||||
}
|
||||
|
||||
if (fullName !== null) {
|
||||
this.user.fullName = fullName;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async uploadPicture(file, scale=1.0) {
|
||||
const formData = new FormData();
|
||||
formData.append("scale", scale);
|
||||
formData.append("picture", file, file.name);
|
||||
let res = await this.apiCall("user/uploadPicture", formData);
|
||||
if (res.success) {
|
||||
this.user.profilePicture = res.profilePicture;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async removePicture() {
|
||||
let res = await this.apiCall("user/removePicture");
|
||||
if (res.success) {
|
||||
this.user.profilePicture = null;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Stats **/
|
||||
@@ -234,8 +267,8 @@ export default class API {
|
||||
}
|
||||
|
||||
/** ApiKeyAPI **/
|
||||
async getApiKeys(showActiveOnly = false) {
|
||||
return this.apiCall("apiKey/fetch", { showActiveOnly: showActiveOnly });
|
||||
async getApiKeys(showActiveOnly = false, page = 1, count = 25, orderBy = "validUntil", sortOrder = "desc") {
|
||||
return this.apiCall("apiKey/fetch", { showActiveOnly: showActiveOnly, pageNum: page, count: count, orderBy: orderBy, sortOrder: sortOrder });
|
||||
}
|
||||
|
||||
async createApiKey() {
|
||||
@@ -248,11 +281,21 @@ export default class API {
|
||||
|
||||
/** 2FA API **/
|
||||
async confirmTOTP(code) {
|
||||
return this.apiCall("tfa/confirmTotp", { code: code });
|
||||
let res = await this.apiCall("tfa/confirmTotp", { code: code });
|
||||
if (res.success) {
|
||||
this.user.twoFactorToken = { type: "totp", confirmed: true };
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async remove2FA(password) {
|
||||
return this.apiCall("tfa/remove", { password: password });
|
||||
let res = await this.apiCall("tfa/remove", { password: password });
|
||||
if (res.success) {
|
||||
this.user.twoFactorToken = null;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async verifyTotp2FA(code) {
|
||||
@@ -264,12 +307,22 @@ export default class API {
|
||||
}
|
||||
|
||||
async register2FA(clientDataJSON = null, attestationObject = null) {
|
||||
return this.apiCall("tfa/registerKey", { clientDataJSON: clientDataJSON, attestationObject: attestationObject });
|
||||
let res = await this.apiCall("tfa/registerKey", { clientDataJSON: clientDataJSON, attestationObject: attestationObject });
|
||||
if (res.success && res.twoFactorToken) {
|
||||
this.user.twoFactorToken = res.twoFactorToken;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** GPG API **/
|
||||
async uploadGPG(pubkey) {
|
||||
return this.apiCall("user/importGPG", { pubkey: pubkey });
|
||||
let res = await this.apiCall("user/importGPG", { pubkey: pubkey });
|
||||
if (res.success) {
|
||||
this.user.gpgKey = res.gpgKey;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async confirmGpgToken(token) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import {LocaleContext} from "../locale";
|
||||
import clsx from "clsx";
|
||||
import {Box, IconButton} from "@mui/material";
|
||||
import {formatDateTime} from "../util";
|
||||
import UserLink from "security-lab/src/elements/user/userlink";
|
||||
import CachedIcon from "@material-ui/icons/Cached";
|
||||
|
||||
|
||||
@@ -137,6 +136,7 @@ export class DataColumn {
|
||||
this.field = field;
|
||||
this.sortable = !params.hasOwnProperty("sortable") || !!params.sortable;
|
||||
this.align = params.align || "left";
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
@@ -152,6 +152,16 @@ export class StringColumn extends DataColumn {
|
||||
constructor(label, field = null, params = {}) {
|
||||
super(label, field, params);
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
let data = super.renderData(L, entry, index);
|
||||
|
||||
if (this.params.style) {
|
||||
data = <span style={this.params.style}>{data}</span>
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export class NumericColumn extends DataColumn {
|
||||
@@ -198,13 +208,14 @@ export class DateTimeColumn extends DataColumn {
|
||||
}
|
||||
}
|
||||
|
||||
export class UserLinkColumn extends DataColumn {
|
||||
export class BoolColumn extends DataColumn {
|
||||
constructor(label, field = null, params = {}) {
|
||||
super(label, field, params);
|
||||
}
|
||||
|
||||
renderData(L, entry, index) {
|
||||
return <UserLink user={super.renderData(L, entry)}/>
|
||||
let data = super.renderData(L, entry);
|
||||
return L(data ? "general.true" : "general.false");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import {Box, Modal} from "@mui/material";
|
||||
import {Button, Typography} from "@material-ui/core";
|
||||
import React, {useContext} from "react";
|
||||
import {Dialog as MuiDialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from "@mui/material";
|
||||
import {Button} from "@material-ui/core";
|
||||
import {LocaleContext} from "../locale";
|
||||
import "./dialog.css";
|
||||
|
||||
export default function Dialog(props) {
|
||||
@@ -11,6 +11,8 @@ export default function Dialog(props) {
|
||||
const onOption = props.onOption || function() { };
|
||||
const options = props.options || ["Close"];
|
||||
const type = props.type || "default";
|
||||
const {translate: L} = useContext(LocaleContext);
|
||||
|
||||
|
||||
let buttons = [];
|
||||
for (let name of options) {
|
||||
@@ -26,20 +28,19 @@ export default function Dialog(props) {
|
||||
)
|
||||
}
|
||||
|
||||
return <Modal
|
||||
return <MuiDialog
|
||||
open={show}
|
||||
onClose={onClose}
|
||||
aria-labelledby="modal-title"
|
||||
aria-describedby="modal-description"
|
||||
>
|
||||
<Box className={clsx("modal-dialog", props.className)}>
|
||||
<Typography id="modal-title" variant="h6" component="h2">
|
||||
{props.title}
|
||||
</Typography>
|
||||
<Typography id="modal-description" sx={{ mt: 2 }}>
|
||||
{props.message}
|
||||
</Typography>
|
||||
{ buttons }
|
||||
</Box>
|
||||
</Modal>
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description">
|
||||
<DialogTitle>{ props.title }</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{ props.message }
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{buttons}
|
||||
</DialogActions>
|
||||
</MuiDialog>
|
||||
}
|
||||
@@ -185,7 +185,7 @@ export default function LoginForm(props) {
|
||||
}).catch(e => {
|
||||
set2FAToken({ ...tfaToken, step: 2, error: e.toString() });
|
||||
});
|
||||
}, [api.loggedIn, tfaToken, props.onLogin, abortSignal]);
|
||||
}, [api.loggedIn, tfaToken, props.onLogin, props.onKey2FA, abortSignal]);
|
||||
|
||||
const createForm = () => {
|
||||
|
||||
@@ -335,7 +335,10 @@ export default function LoginForm(props) {
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
return <b>{L("general.loading")}… <Icon icon={"spinner"}/></b>
|
||||
return <Box textAlign={"center"} mt={2}>
|
||||
<h2>{L("general.loading", "Loading")}…</h2>
|
||||
<CircularProgress size={"32px"}/>
|
||||
</Box>
|
||||
}
|
||||
|
||||
let successMessage = getParameter("success");
|
||||
|
||||
Reference in New Issue
Block a user