fix(fe): enable captcha at user level
This commit is contained in:
parent
b0e280ee70
commit
99b424ee2a
9 changed files with 54 additions and 87 deletions
|
@ -89,12 +89,10 @@ export interface GetSharingDirResp {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientConfigMsg {
|
export interface ClientConfigMsg {
|
||||||
clientCfg: ClientConfig;
|
|
||||||
}
|
|
||||||
export interface ClientConfig {
|
|
||||||
siteName: string;
|
siteName: string;
|
||||||
siteDesc: string;
|
siteDesc: string;
|
||||||
bg: BgConfig;
|
bg: BgConfig;
|
||||||
|
captchaEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientErrorReport {
|
export interface ClientErrorReport {
|
||||||
|
@ -154,7 +152,7 @@ export interface IFilesClient {
|
||||||
export interface ISettingsClient {
|
export interface ISettingsClient {
|
||||||
health: () => Promise<Response>;
|
health: () => Promise<Response>;
|
||||||
getClientCfg: () => Promise<Response>;
|
getClientCfg: () => Promise<Response>;
|
||||||
setClientCfg: (cfg: ClientConfig) => Promise<Response>;
|
setClientCfg: (cfg: ClientConfigMsg) => Promise<Response>;
|
||||||
reportErrors: (reports: List<ClientErrorReport>) => Promise<Response>;
|
reportErrors: (reports: List<ClientErrorReport>) => Promise<Response>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
|
|
||||||
import { BaseClient, Response, userIDParam, Quota } from ".";
|
import { BaseClient, Response, userIDParam, Quota } from ".";
|
||||||
import { ClientConfig, ClientErrorReport } from "./";
|
import { ClientConfigMsg, ClientErrorReport } from "./";
|
||||||
|
|
||||||
export class SettingsClient extends BaseClient {
|
export class SettingsClient extends BaseClient {
|
||||||
constructor(url: string) {
|
constructor(url: string) {
|
||||||
|
@ -22,13 +22,11 @@ export class SettingsClient extends BaseClient {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setClientCfg = (cfg: ClientConfig): Promise<Response> => {
|
setClientCfg = (cfg: ClientConfigMsg): Promise<Response> => {
|
||||||
return this.do({
|
return this.do({
|
||||||
method: "patch",
|
method: "patch",
|
||||||
url: `${this.url}/v1/settings/client`,
|
url: `${this.url}/v1/settings/client`,
|
||||||
data: {
|
data: cfg,
|
||||||
clientCfg: cfg,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ export const resps = {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "",
|
statusText: "",
|
||||||
data: {
|
data: {
|
||||||
clientCfg: {
|
|
||||||
siteName: "",
|
siteName: "",
|
||||||
siteDesc: "",
|
siteDesc: "",
|
||||||
bg: {
|
bg: {
|
||||||
|
@ -26,48 +25,12 @@ export const resps = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
reportErrorsMockResp: {
|
reportErrorsMockResp: {
|
||||||
status: 200,
|
status: 200,
|
||||||
statusText: "",
|
statusText: "",
|
||||||
data: {},
|
data: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export class MockSettingsClient {
|
|
||||||
private url: string;
|
|
||||||
private resps: SettingsClientResps;
|
|
||||||
|
|
||||||
constructor(url: string) {
|
|
||||||
this.url = url;
|
|
||||||
this.resps = resps;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMock = (resps: SettingsClientResps) => {
|
|
||||||
this.resps = resps;
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapPromise = (resp: any): Promise<any> => {
|
|
||||||
return new Promise<any>((resolve) => {
|
|
||||||
resolve(resp);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
health = (): Promise<Response> => {
|
|
||||||
return this.wrapPromise(this.resps.healthMockResp);
|
|
||||||
};
|
|
||||||
|
|
||||||
setClientCfg = (): Promise<Response> => {
|
|
||||||
return this.wrapPromise(this.resps.setClientCfgMockResp);
|
|
||||||
};
|
|
||||||
|
|
||||||
getClientCfg = (): Promise<Response> => {
|
|
||||||
return this.wrapPromise(this.resps.getClientCfgMockResp);
|
|
||||||
};
|
|
||||||
|
|
||||||
reportErrors = (): Promise<Response> => {
|
|
||||||
return this.wrapPromise(this.resps.reportErrorsMockResp);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class JestSettingsClient {
|
export class JestSettingsClient {
|
||||||
url: string = "";
|
url: string = "";
|
||||||
|
|
|
@ -34,6 +34,7 @@ describe("Login", () => {
|
||||||
const pane = new AuthPane({
|
const pane = new AuthPane({
|
||||||
login: coreState.login,
|
login: coreState.login,
|
||||||
msg: coreState.msg,
|
msg: coreState.msg,
|
||||||
|
ui: coreState.ui,
|
||||||
update: (updater: (prevState: ICoreState) => ICoreState) => {},
|
update: (updater: (prevState: ICoreState) => ICoreState) => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ describe("State Manager", () => {
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
expect(coreState.ui.bg).toEqual(
|
expect(coreState.ui.bg).toEqual(
|
||||||
settingsResps.getClientCfgMockResp.data.clientCfg.bg
|
settingsResps.getClientCfgMockResp.data.bg
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ describe("State Manager", () => {
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
expect(coreState.ui.bg).toEqual(
|
expect(coreState.ui.bg).toEqual(
|
||||||
settingsResps.getClientCfgMockResp.data.clientCfg.bg
|
settingsResps.getClientCfgMockResp.data.bg
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ export interface UIProps {
|
||||||
isVertical: boolean;
|
isVertical: boolean;
|
||||||
siteName: string;
|
siteName: string;
|
||||||
siteDesc: string;
|
siteDesc: string;
|
||||||
|
captchaEnabled: boolean;
|
||||||
bg: {
|
bg: {
|
||||||
url: string;
|
url: string;
|
||||||
repeat: string;
|
repeat: string;
|
||||||
|
@ -111,6 +112,7 @@ export function initState(): ICoreState {
|
||||||
position: "",
|
position: "",
|
||||||
align: "",
|
align: "",
|
||||||
},
|
},
|
||||||
|
captchaEnabled: true,
|
||||||
control: {
|
control: {
|
||||||
controls: Map<string, string>({
|
controls: Map<string, string>({
|
||||||
[panelTabs]: "filesPanel",
|
[panelTabs]: "filesPanel",
|
||||||
|
|
|
@ -57,6 +57,7 @@ export class Layers extends React.Component<Props, State, {}> {
|
||||||
<div id="root-container">
|
<div id="root-container">
|
||||||
<AuthPane
|
<AuthPane
|
||||||
login={this.props.login}
|
login={this.props.login}
|
||||||
|
ui={this.props.ui}
|
||||||
update={this.props.update}
|
update={this.props.update}
|
||||||
msg={this.props.msg}
|
msg={this.props.msg}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
|
|
||||||
import { ICoreState, MsgProps } from "./core_state";
|
import { ICoreState, MsgProps, UIProps } from "./core_state";
|
||||||
import { Flexbox } from "./layout/flexbox";
|
import { Flexbox } from "./layout/flexbox";
|
||||||
import { updater } from "./state_updater";
|
import { updater } from "./state_updater";
|
||||||
import { alertMsg } from "../common/env";
|
import { alertMsg } from "../common/env";
|
||||||
|
@ -26,6 +26,7 @@ export interface LoginProps {
|
||||||
export interface Props {
|
export interface Props {
|
||||||
login: LoginProps;
|
login: LoginProps;
|
||||||
msg: MsgProps;
|
msg: MsgProps;
|
||||||
|
ui: UIProps;
|
||||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +107,34 @@ export class AuthPane extends React.Component<Props, State, {}> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const row3 = this.props.ui.captchaEnabled ? (
|
||||||
|
<Flexbox
|
||||||
|
children={List([
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input
|
||||||
|
id="captcha-input"
|
||||||
|
type="text"
|
||||||
|
onChange={this.changeCaptcha}
|
||||||
|
value={this.state.captchaInput}
|
||||||
|
placeholder={this.props.msg.pkg.get("login.captcha")}
|
||||||
|
/>
|
||||||
|
</div>,
|
||||||
|
|
||||||
|
<img
|
||||||
|
id="captcha"
|
||||||
|
src={`/v1/captchas/imgs?capid=${this.props.login.captchaID}`}
|
||||||
|
className={`captcha ${this.state.captchaLoaded ? "" : "hidden"}`}
|
||||||
|
onClick={this.refreshCaptcha}
|
||||||
|
onLoad={() => this.setState({ captchaLoaded: true })}
|
||||||
|
/>,
|
||||||
|
])}
|
||||||
|
childrenStyles={List([
|
||||||
|
{ justifyContent: "flex-start" },
|
||||||
|
{ justifyContent: "flex-end" },
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="pane-login"
|
id="pane-login"
|
||||||
|
@ -144,33 +173,7 @@ export class AuthPane extends React.Component<Props, State, {}> {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Flexbox
|
{row3}
|
||||||
children={List([
|
|
||||||
<div className="input-wrap">
|
|
||||||
<input
|
|
||||||
id="captcha-input"
|
|
||||||
type="text"
|
|
||||||
onChange={this.changeCaptcha}
|
|
||||||
value={this.state.captchaInput}
|
|
||||||
placeholder={this.props.msg.pkg.get("login.captcha")}
|
|
||||||
/>
|
|
||||||
</div>,
|
|
||||||
|
|
||||||
<img
|
|
||||||
id="captcha"
|
|
||||||
src={`/v1/captchas/imgs?capid=${this.props.login.captchaID}`}
|
|
||||||
className={`captcha ${
|
|
||||||
this.state.captchaLoaded ? "" : "hidden"
|
|
||||||
}`}
|
|
||||||
onClick={this.refreshCaptcha}
|
|
||||||
onLoad={() => this.setState({ captchaLoaded: true })}
|
|
||||||
/>,
|
|
||||||
])}
|
|
||||||
childrenStyles={List([
|
|
||||||
{ justifyContent: "flex-start" },
|
|
||||||
{ justifyContent: "flex-end" },
|
|
||||||
])}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button id="btn-login" onClick={this.login}>
|
<button id="btn-login" onClick={this.login}>
|
||||||
{this.props.msg.pkg.get("login.login")}
|
{this.props.msg.pkg.get("login.login")}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
roleUser,
|
roleUser,
|
||||||
roleAdmin,
|
roleAdmin,
|
||||||
visitorID,
|
visitorID,
|
||||||
ClientConfig,
|
ClientConfigMsg,
|
||||||
Preferences,
|
Preferences,
|
||||||
} from "../client";
|
} from "../client";
|
||||||
import { FilesClient, shareIDQuery, shareDirQuery } from "../client/files";
|
import { FilesClient, shareIDQuery, shareDirQuery } from "../client/files";
|
||||||
|
@ -780,12 +780,12 @@ export class Updater {
|
||||||
return resp.status === 200 ? "" : errServer;
|
return resp.status === 200 ? "" : errServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
setClientCfgRemote = async (cfg: ClientConfig): Promise<string> => {
|
setClientCfgRemote = async (cfg: ClientConfigMsg): Promise<string> => {
|
||||||
const resp = await this.settingsClient.setClientCfg(cfg);
|
const resp = await this.settingsClient.setClientCfg(cfg);
|
||||||
return resp.status === 200 ? "" : errServer;
|
return resp.status === 200 ? "" : errServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
setClientCfg = (cfg: ClientConfig) => {
|
setClientCfg = (cfg: ClientConfigMsg) => {
|
||||||
this.props.ui = {
|
this.props.ui = {
|
||||||
...this.props.ui,
|
...this.props.ui,
|
||||||
siteName: cfg.siteName,
|
siteName: cfg.siteName,
|
||||||
|
@ -810,10 +810,11 @@ export class Updater {
|
||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
return errServer;
|
return errServer;
|
||||||
}
|
}
|
||||||
const clientCfg = resp.data.clientCfg as ClientConfig;
|
const clientCfg = resp.data as ClientConfigMsg;
|
||||||
this.props.ui.siteName = clientCfg.siteName;
|
this.props.ui.siteName = clientCfg.siteName;
|
||||||
this.props.ui.siteDesc = clientCfg.siteDesc;
|
this.props.ui.siteDesc = clientCfg.siteDesc;
|
||||||
this.props.ui.bg = clientCfg.bg;
|
this.props.ui.bg = clientCfg.bg;
|
||||||
|
this.props.ui.captchaEnabled = clientCfg.captchaEnabled;
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue