Revert "making databag pretty, thanks @lil5"

This reverts commit afb7632edf.
This commit is contained in:
Roland Osborne 2024-05-02 15:16:20 -07:00
parent d38d60119b
commit 55e054abb5
231 changed files with 4313 additions and 6447 deletions

View File

@ -1,39 +1,21 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link <link rel="icon" href="/favicon.ico" />
rel="icon" <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
href="/favicon.ico" <meta name="theme-color" content="#000000" />
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta
name="theme-color"
content="#000000"
/>
<meta <meta
name="Databag" name="Databag"
content="Communication for the Decentralized Web" content="Communication for the Decentralized Web"
/> />
<link <link rel="apple-touch-icon" href="/logo192.png" />
rel="apple-touch-icon" <link rel="manifest" href="/manifest.json" />
href="/logo192.png"
/>
<link
rel="manifest"
href="/manifest.json"
/>
<title>Databag</title> <title>Databag</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<script <script type="module" src="/src/index.tsx"></script>
type="module"
src="/src/index.tsx"
></script>
</body> </body>
</html> </html>

View File

@ -1 +1,2 @@
module.exports = ''; module.exports = '';

View File

@ -1,6 +1,7 @@
import 'antd/dist/reset.css'; import 'antd/dist/reset.css';
import { Colors } from 'constants/Colors'; import { Colors } from 'constants/Colors';
import { HashRouter as Router, Routes, Route } from 'react-router-dom'; import { HashRouter as Router, Routes, Route } from "react-router-dom";
import { AppContextProvider } from 'context/AppContext'; import { AppContextProvider } from 'context/AppContext';
import { AccountContextProvider } from 'context/AccountContext'; import { AccountContextProvider } from 'context/AccountContext';
@ -22,6 +23,7 @@ import { Dashboard } from './dashboard/Dashboard';
import { ConfigProvider } from 'antd'; import { ConfigProvider } from 'antd';
function App() { function App() {
return ( return (
<UploadContextProvider> <UploadContextProvider>
<ChannelContextProvider> <ChannelContextProvider>
@ -33,46 +35,25 @@ function App() {
<SettingsContextProvider> <SettingsContextProvider>
<AppContextProvider> <AppContextProvider>
<AppWrapper> <AppWrapper>
<ConfigProvider <ConfigProvider theme={{ token: {
theme={{ colorPrimary: Colors.primary,
token: { colorLink: Colors.primary,
colorPrimary: Colors.primary, colorLinkHover: Colors.background,
colorLink: Colors.primary, colorBgBase: Colors.cancel,
colorLinkHover: Colors.background, } }}>
colorBgBase: Colors.cancel,
},
}}
>
<Router> <Router>
<Routes> <Routes>
<Route <Route path="/" element={ <Root /> } />
path="/" <Route path="/dashboard" element={ <Dashboard /> } />
element={<Root />} <Route path="/admin" element={ <Access mode="admin" /> } />
/> <Route path="/login" element={ <Access mode="login" /> } />
<Route <Route path="/create" element={ <Access mode="create" /> } />
path="/dashboard" <Route path="/session" element={
element={<Dashboard />} <ConversationContextProvider>
/> <Session />
<Route </ConversationContextProvider>
path="/admin" }>
element={<Access mode="admin" />} </Route>
/>
<Route
path="/login"
element={<Access mode="login" />}
/>
<Route
path="/create"
element={<Access mode="create" />}
/>
<Route
path="/session"
element={
<ConversationContextProvider>
<Session />
</ConversationContextProvider>
}
></Route>
</Routes> </Routes>
</Router> </Router>
</ConfigProvider> </ConfigProvider>

View File

@ -2,7 +2,7 @@ import styled from 'styled-components';
export const AccessWrapper = styled.div` export const AccessWrapper = styled.div`
height: 100%; height: 100%;
color: ${(props) => props.theme.hintText}; color: ${props => props.theme.hintText};
.footer { .footer {
display: flex; display: flex;
@ -27,7 +27,7 @@ export const AccessWrapper = styled.div`
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 4px; border-radius: 4px;
background: ${(props) => props.theme.frameArea}; background: ${props => props.theme.frameArea};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -44,7 +44,7 @@ export const AccessWrapper = styled.div`
width: 50%; width: 50%;
height: 100%; height: 100%;
padding: 32px; padding: 32px;
background-color: ${(props) => props.theme.splashArea}; background-color: ${props => props.theme.splashArea};
.splash { .splash {
width: 100%; width: 100%;
@ -56,7 +56,7 @@ export const AccessWrapper = styled.div`
.right { .right {
width: 50%; width: 50%;
height: 100%; height: 100%;
background: ${(props) => props.theme.frameArea}; background: ${props => props.theme.frameArea};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;

View File

@ -3,98 +3,104 @@ import { AccessWrapper } from './Access.styled';
import { Login } from './login/Login'; import { Login } from './login/Login';
import { Admin } from './admin/Admin'; import { Admin } from './admin/Admin';
import { CreateAccount } from './createAccount/CreateAccount'; import { CreateAccount } from './createAccount/CreateAccount';
import { ThemeProvider } from 'styled-components'; import { ThemeProvider } from "styled-components";
import { Select } from 'antd'; import { Select } from 'antd';
import dogin from 'images/dogin.png'; import dogin from 'images/dogin.png';
import bogin from 'images/bogin.png'; import bogin from 'images/bogin.png';
export function Access({ mode }) { export function Access({ mode }) {
const { state, actions } = useAccess(); const { state, actions } = useAccess();
return ( return (
<ThemeProvider theme={state.colors}> <ThemeProvider theme={state.colors}>
<AccessWrapper> <AccessWrapper>
{(state.display === 'large' || state.display === 'xlarge') && ( { (state.display === 'large' || state.display === 'xlarge') && (
<div className="split-layout"> <div className="split-layout">
<div className="left"> <div className="left">
{state.scheme === 'dark' && ( { state.scheme === 'dark' && (
<img <img className="splash" src={dogin} alt="Databag Splash" />
className="splash"
src={dogin}
alt="Databag Splash"
/>
)} )}
{state.scheme === 'light' && ( { state.scheme === 'light' && (
<img <img className="splash" src={bogin} alt="Databag Splash" />
className="splash"
src={bogin}
alt="Databag Splash"
/>
)} )}
</div> </div>
<div className="right"> <div className="right">
{mode === 'login' && <Login />} { mode === 'login' && (
{mode === 'create' && <CreateAccount />} <Login />
{mode === 'admin' && <Admin />} )}
{ mode === 'create' && (
<CreateAccount />
)}
{ mode === 'admin' && (
<Admin />
)}
<div className="footer"> <div className="footer">
<div className="option"> <div className="option">
<div className="label">{state.strings.theme}</div> <div className="label">{state.strings.theme}</div>
<Select <Select
defaultValue={null} defaultValue={null}
size="small" size="small"
style={{ width: 128 }} style={{ width: 128 }}
value={state.theme} value={state.theme}
onChange={actions.setTheme} onChange={actions.setTheme}
options={[{ value: null, label: state.strings.default }, ...state.themes]} options={[{value: null, label: state.strings.default}, ...state.themes]}
/> />
</div> </div>
<div className="option"> <div className="option">
<div className="label">{state.strings.language}</div> <div className="label">{state.strings.language}</div>
<Select <Select
defaultValue={null} defaultValue={null}
size="small" size="small"
style={{ width: 128 }} style={{ width: 128 }}
value={state.language} value={state.language}
onChange={actions.setLanguage} onChange={actions.setLanguage}
options={[{ value: null, label: state.strings.default }, ...state.languages]} options={[{value: null, label: state.strings.default}, ...state.languages]}
/> />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
)} )}
{(state.display === 'medium' || state.display === 'small') && ( { (state.display === 'medium' || state.display === 'small') && (
<div className="full-layout"> <div className="full-layout">
<div className="center"> <div className="center">
{mode === 'login' && <Login />} { mode === 'login' && (
{mode === 'create' && <CreateAccount />} <Login />
{mode === 'admin' && <Admin />} )}
{ mode === 'create' && (
<CreateAccount />
)}
{ mode === 'admin' && (
<Admin />
)}
<div className="footer"> <div className="footer">
<div className="option"> <div className="option">
<div className="label">{state.strings.theme}</div> <div className="label">{state.strings.theme}</div>
<Select <Select
defaultValue={null} defaultValue={null}
size="small" size="small"
style={{ width: 128 }} style={{ width: 128 }}
value={state.theme} value={state.theme}
onChange={actions.setTheme} onChange={actions.setTheme}
options={[{ value: null, label: state.strings.default }, ...state.themes]} options={[{value: null, label: state.strings.default}, ...state.themes]}
/> />
</div> </div>
<div className="option"> <div className="option">
<div className="label">{state.strings.language}</div> <div className="label">{state.strings.language}</div>
<Select <Select
defaultValue={null} defaultValue={null}
size="small" size="small"
style={{ width: 128 }} style={{ width: 128 }}
value={state.language} value={state.language}
onChange={actions.setLanguage} onChange={actions.setLanguage}
options={[{ value: null, label: state.strings.default }, ...state.languages]} options={[{value: null, label: state.strings.default}, ...state.languages]}
/> />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
)} )}
@ -102,3 +108,4 @@ export function Access({ mode }) {
</ThemeProvider> </ThemeProvider>
); );
} }

View File

@ -9,18 +9,18 @@ export const AdminWrapper = styled.div`
flex-direction: column; flex-direction: column;
.disabled { .disabled {
background-color: ${(props) => props.theme.disabledArea}; background-color: ${props => props.theme.disabledArea};
button { button {
color: ${(props) => props.theme.idleText}; color: ${props => props.theme.idleText};
} }
} }
.enabled { .enabled {
background-color: ${(props) => props.theme.enabledArea}; background-color: ${props => props.theme.enabledArea};
button { button {
color: ${(props) => props.theme.activeText}; color: ${props => props.theme.activeText};
} }
} }
@ -70,3 +70,5 @@ export const AdminWrapper = styled.div`
background-color: #444444; background-color: #444444;
} }
`; `;

View File

@ -3,75 +3,59 @@ import { UserOutlined, LockOutlined } from '@ant-design/icons';
import { AdminWrapper } from './Admin.styled'; import { AdminWrapper } from './Admin.styled';
import { useAdmin } from './useAdmin.hook'; import { useAdmin } from './useAdmin.hook';
export function Admin() { export function Admin() {
const [modal, modalContext] = Modal.useModal();
const [ modal, modalContext ] = Modal.useModal();
const { state, actions } = useAdmin(); const { state, actions } = useAdmin();
const login = async () => { const login = async () => {
try { try {
await actions.login(); await actions.login();
} catch (err) { }
catch(err) {
modal.error({ modal.error({
title: <span style={state.menuStyle}>{state.strings.adminError}</span>, title: <span style={state.menuStyle}>{state.strings.adminError}</span>,
content: <span style={state.menuStyle}>{state.strings.adminMessage}</span>, content: <span style={state.menuStyle}>{state.strings.adminMessage}</span>,
bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
}); });
} }
}; }
const keyDown = (e) => { const keyDown = (e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
login(); login()
} }
}; }
return ( return (
<AdminWrapper> <AdminWrapper>
{modalContext} { modalContext }
<div className="app-title"> <div className="app-title">
<span>Databag</span> <span>Databag</span>
<div <div className="settings" onClick={() => actions.navUser()}>
className="settings"
onClick={() => actions.navUser()}
>
<UserOutlined /> <UserOutlined />
</div> </div>
</div> </div>
<div className="form-title">{state.strings.admin}</div> <div className="form-title">{state.strings.admin}</div>
<div className="form-form"> <div className="form-form">
<Form <Form name="basic" wrapperCol={{ span: 24, }}>
name="basic"
wrapperCol={{ span: 24 }}
>
<Form.Item name="password"> <Form.Item name="password">
<Input.Password <Input.Password placeholder={ state.unclaimed ? state.strings.newPassword : state.strings.password } spellCheck="false"
placeholder={state.unclaimed ? state.strings.newPassword : state.strings.password} onChange={(e) => actions.setPassword(e.target.value)} autoComplete="current-password"
spellCheck="false" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} size="large" />
onChange={(e) => actions.setPassword(e.target.value)}
autoComplete="current-password"
onKeyDown={(e) => keyDown(e)}
prefix={<LockOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<div className="form-button"> <div className="form-button">
<div className="form-login"> <div className="form-login">
<Button <Button className={state.password ? 'enabled' : 'disabled'} type="primary" block onClick={login} size="middle" loading={state.busy}
className={state.password ? 'enabled' : 'disabled'} disabled={!state.password}>{state.strings.login}</Button>
type="primary"
block
onClick={login}
size="middle"
loading={state.busy}
disabled={!state.password}
>
{state.strings.login}
</Button>
</div> </div>
</div> </div>
</Form> </Form>
</div> </div>
</AdminWrapper> </AdminWrapper>
); );
} };

View File

@ -1,5 +1,5 @@
import { useContext, useState, useEffect } from 'react'; import { useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
import { getNodeStatus } from 'api/getNodeStatus'; import { getNodeStatus } from 'api/getNodeStatus';
import { setNodeStatus } from 'api/setNodeStatus'; import { setNodeStatus } from 'api/setNodeStatus';
import { getNodeConfig } from 'api/getNodeConfig'; import { getNodeConfig } from 'api/getNodeConfig';
@ -7,6 +7,7 @@ import { AppContext } from 'context/AppContext';
import { SettingsContext } from 'context/SettingsContext'; import { SettingsContext } from 'context/SettingsContext';
export function useAdmin() { export function useAdmin() {
const [state, setState] = useState({ const [state, setState] = useState({
password: '', password: '',
placeholder: '', placeholder: '',
@ -22,15 +23,16 @@ export function useAdmin() {
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
}; }
useEffect(() => { useEffect(() => {
const check = async () => { const check = async () => {
try { try {
const unclaimed = await getNodeStatus(); const unclaimed = await getNodeStatus();
updateState({ unclaimed }); updateState({ unclaimed });
} catch (err) { }
console.log('getNodeStatus failed'); catch(err) {
console.log("getNodeStatus failed");
} }
}; };
check(); check();
@ -53,14 +55,15 @@ export function useAdmin() {
await getNodeConfig(state.password); await getNodeConfig(state.password);
updateState({ busy: false }); updateState({ busy: false });
app.actions.setAdmin(state.password); app.actions.setAdmin(state.password);
} catch (err) { }
catch(err) {
console.log(err); console.log(err);
updateState({ busy: false }); updateState({ busy: false });
throw new Error('login failed'); throw new Error("login failed");
} }
} }
}, },
}; }
useEffect(() => { useEffect(() => {
const { strings, menuStyle } = settings.state; const { strings, menuStyle } = settings.state;
@ -69,3 +72,4 @@ export function useAdmin() {
return { state, actions }; return { state, actions };
} }

View File

@ -9,18 +9,18 @@ export const CreateAccountWrapper = styled.div`
flex-direction: column; flex-direction: column;
.disabled { .disabled {
background-color: ${(props) => props.theme.disabledArea}; background-color: ${props => props.theme.disabledArea};
button { button {
color: ${(props) => props.theme.idleText}; color: ${props => props.theme.idleText};
} }
} }
.enabled { .enabled {
background-color: ${(props) => props.theme.enabledArea}; background-color: ${props => props.theme.enabledArea};
button { button {
color: ${(props) => props.theme.activeText}; color: ${props => props.theme.activeText};
} }
} }
@ -78,3 +78,5 @@ export const CreateAccountWrapper = styled.div`
background-color: #444444; background-color: #444444;
} }
`; `;

View File

@ -3,100 +3,64 @@ import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import { CreateAccountWrapper } from './CreateAccount.styled'; import { CreateAccountWrapper } from './CreateAccount.styled';
import { useCreateAccount } from './useCreateAccount.hook'; import { useCreateAccount } from './useCreateAccount.hook';
export function CreateAccount() { export function CreateAccount() {
const [modal, modalContext] = Modal.useModal();
const [ modal, modalContext ] = Modal.useModal();
const { state, actions } = useCreateAccount(); const { state, actions } = useCreateAccount();
const create = async () => { const create = async () => {
try { try {
await actions.onCreateAccount(); await actions.onCreateAccount();
} catch (err) { }
catch(err) {
modal.error({ modal.error({
title: <span style={state.menuStyle}>{state.strings.createError}</span>, title: <span style={state.menuStyle}>{state.strings.createError}</span>,
content: <span style={state.menuStyle}>{state.strings.createMessage}</span>, content: <span style={state.menuStyle}>{state.strings.createMessage}</span>,
bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
}); });
} }
}; }
const keyDown = (e) => { const keyDown = (e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
create(); create()
} }
}; }
return ( return (
<CreateAccountWrapper> <CreateAccountWrapper>
{modalContext} { modalContext }
<div className="app-title"> <div className="app-title">
<span>Databag</span> <span>Databag</span>
<div <div className="settings" onClick={() => actions.onSettings()}>
className="settings"
onClick={() => actions.onSettings()}
>
<SettingOutlined /> <SettingOutlined />
</div> </div>
</div> </div>
<div className="form-title">{state.strings.createAccount}</div> <div className="form-title">{state.strings.createAccount}</div>
<div className="form-form"> <div className="form-form">
<Form <Form name="basic" wrapperCol={{ span: 24, }}>
name="basic"
wrapperCol={{ span: 24 }} <Form.Item name="username" validateStatus={state.validateStatus} help={state.help}>
> <Input placeholder={state.strings.username} spellCheck="false" onChange={(e) => actions.setUsername(e.target.value)}
<Form.Item autoComplete="username" autoCapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={<UserOutlined />} size="large" />
name="username"
validateStatus={state.validateStatus}
help={state.help}
>
<Input
placeholder={state.strings.username}
spellCheck="false"
onChange={(e) => actions.setUsername(e.target.value)}
autoComplete="username"
autoCapitalize="none"
onKeyDown={(e) => keyDown(e)}
prefix={<UserOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<div className="form-space"></div> <div className="form-space"></div>
<Form.Item name="password"> <Form.Item name="password">
<Input.Password <Input.Password placeholder={state.strings.newPassword} spellCheck="false" onChange={(e) => actions.setPassword(e.target.value)}
placeholder={state.strings.newPassword} autoComplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} size="large" />
spellCheck="false"
onChange={(e) => actions.setPassword(e.target.value)}
autoComplete="new-password"
onKeyDown={(e) => keyDown(e)}
prefix={<LockOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<Form.Item name="confirm"> <Form.Item name="confirm">
<Input.Password <Input.Password placeholder={state.strings.confirmPassword} spellCheck="false" onChange={(e) => actions.setConfirm(e.target.value)}
placeholder={state.strings.confirmPassword} autoComplete="new-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} size="large" />
spellCheck="false"
onChange={(e) => actions.setConfirm(e.target.value)}
autoComplete="new-password"
onKeyDown={(e) => keyDown(e)}
prefix={<LockOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<div className="form-button"> <div className="form-button">
<div className="form-create"> <div className="form-create">
<Button <Button className={actions.isDisabled() ? 'disabled' : 'enabled'} type="primary" block onClick={create} disabled={ actions.isDisabled()}
className={actions.isDisabled() ? 'disabled' : 'enabled'} loading={state.busy} size="middle">
type="primary"
block
onClick={create}
disabled={actions.isDisabled()}
loading={state.busy}
size="middle"
>
{state.strings.create} {state.strings.create}
</Button> </Button>
</div> </div>
@ -104,17 +68,15 @@ export function CreateAccount() {
<div className="form-button"> <div className="form-button">
<div className="form-login"> <div className="form-login">
<Button <Button type="link" block onClick={(e) => actions.onLogin()}>
type="link"
block
onClick={(e) => actions.onLogin()}
>
{state.strings.accountLogin} {state.strings.accountLogin}
</Button> </Button>
</div> </div>
</div> </div>
</Form> </Form>
</div> </div>
</CreateAccountWrapper> </CreateAccountWrapper>
); );
} };

View File

@ -1,10 +1,11 @@
import { useContext, useState, useEffect, useRef } from 'react'; import { useContext, useState, useEffect, useRef } from 'react';
import { AppContext } from 'context/AppContext'; import { AppContext } from 'context/AppContext';
import { SettingsContext } from 'context/SettingsContext'; import { SettingsContext } from 'context/SettingsContext';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from "react-router-dom";
import { getUsername } from 'api/getUsername'; import { getUsername } from 'api/getUsername';
export function useCreateAccount() { export function useCreateAccount() {
const [checked, setChecked] = useState(true); const [checked, setChecked] = useState(true);
const [state, setState] = useState({ const [state, setState] = useState({
username: '', username: '',
@ -13,7 +14,7 @@ export function useCreateAccount() {
busy: false, busy: false,
validatetatus: 'success', validatetatus: 'success',
help: '', help: '',
strings: {} as Record<string, string>, strings: {} as Record<string,string>,
menuStyle: {}, menuStyle: {},
}); });
@ -25,30 +26,33 @@ export function useCreateAccount() {
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
}; }
const usernameSet = (name) => { const usernameSet = (name) => {
setChecked(false); setChecked(false)
clearTimeout(debounce.current); clearTimeout(debounce.current)
debounce.current = setTimeout(async () => { debounce.current = setTimeout(async () => {
if (name !== '') { if (name !== '') {
try { try {
let valid = await getUsername(name, state.token); let valid = await getUsername(name, state.token)
if (!valid) { if (!valid) {
updateState({ validateStatus: 'error', help: 'Username is not available' }); updateState({ validateStatus: 'error', help: 'Username is not available' })
} else {
updateState({ validateStatus: 'success', help: '' });
} }
setChecked(true); else {
} catch (err) { updateState({ validateStatus: 'success', help: '' })
}
setChecked(true)
}
catch(err) {
console.log(err); console.log(err);
} }
} else { }
else {
updateState({ validateStatus: 'success', help: '' }); updateState({ validateStatus: 'success', help: '' });
setChecked(true); setChecked(true);
} }
}, 500); }, 500)
}; }
const actions = { const actions = {
setUsername: (username) => { setUsername: (username) => {
@ -63,32 +67,27 @@ export function useCreateAccount() {
}, },
isDisabled: () => { isDisabled: () => {
const restricted = new RegExp('[!@#$%^&*() ,.?":{}|<>]', 'i'); const restricted = new RegExp('[!@#$%^&*() ,.?":{}|<>]', 'i');
if ( if (state.username === '' || restricted.test(state.username) || state.password === '' ||
state.username === '' || state.password !== state.confirm || !checked || state.validateStatus === 'error') {
restricted.test(state.username) || return true
state.password === '' ||
state.password !== state.confirm ||
!checked ||
state.validateStatus === 'error'
) {
return true;
} }
return false; return false
}, },
onSettings: () => { onSettings: () => {
navigate('/admin'); navigate('/admin');
}, },
onCreateAccount: async () => { onCreateAccount: async () => {
if (!state.busy && state.username !== '' && state.password !== '' && state.password === state.confirm) { if (!state.busy && state.username !== '' && state.password !== '' && state.password === state.confirm) {
updateState({ busy: true }); updateState({ busy: true })
try { try {
await app.actions.create(state.username, state.password, state.token); await app.actions.create(state.username, state.password, state.token)
} catch (err) { }
catch (err) {
console.log(err); console.log(err);
updateState({ busy: false }); updateState({ busy: false })
throw new Error('create failed: check with your admin'); throw new Error('create failed: check with your admin');
} }
updateState({ busy: false }); updateState({ busy: false })
} }
}, },
onLogin: () => { onLogin: () => {
@ -103,11 +102,12 @@ export function useCreateAccount() {
useEffect(() => { useEffect(() => {
let params = new URLSearchParams(search); let params = new URLSearchParams(search);
let token = params.get('add'); let token = params.get("add");
if (token) { if (token) {
updateState({ token }); updateState({ token });
} }
}, [app, navigate, search]); }, [app, navigate, search])
return { state, actions }; return { state, actions };
} }

View File

@ -8,18 +8,18 @@ export const LoginWrapper = styled.div`
flex-direction: column; flex-direction: column;
.disabled { .disabled {
background-color: ${(props) => props.theme.disabledArea}; background-color: ${props => props.theme.disabledArea};
button { button {
color: ${(props) => props.theme.idleText}; color: ${props => props.theme.idleText};
} }
} }
.enabled { .enabled {
background-color: ${(props) => props.theme.enabledArea}; background-color: ${props => props.theme.enabledArea};
button { button {
color: ${(props) => props.theme.activeText}; color: ${props => props.theme.activeText};
} }
} }
@ -29,10 +29,10 @@ export const LoginWrapper = styled.div`
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
flex: 1; flex: 1;
color: ${(props) => props.theme.hintText}; color: ${props => props.theme.hintText};
.settings { .settings {
color: ${(props) => props.theme.hintText}; color: ${props => props.theme.hintText};
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 0px; right: 0px;
@ -79,3 +79,5 @@ export const LoginWrapper = styled.div`
background-color: #444444; background-color: #444444;
} }
`; `;

View File

@ -3,103 +3,77 @@ import { SettingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import { LoginWrapper } from './Login.styled'; import { LoginWrapper } from './Login.styled';
import { useLogin } from './useLogin.hook'; import { useLogin } from './useLogin.hook';
export function Login() { export function Login() {
const [modal, modalContext] = Modal.useModal();
const [ modal, modalContext ] = Modal.useModal();
const { state, actions } = useLogin(); const { state, actions } = useLogin();
const login = async () => { const login = async () => {
try { try {
await actions.onLogin(); await actions.onLogin();
} catch (err) { }
catch(err) {
modal.error({ modal.error({
title: <span style={state.menuStyle}>{state.strings.loginError}</span>, title: <span style={state.menuStyle}>{state.strings.loginError}</span>,
content: <span style={state.menuStyle}>{state.strings.loginMessage}</span>, content: <span style={state.menuStyle}>{state.strings.loginMessage}</span>,
bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
}); });
} }
}; }
const keyDown = (e) => { const keyDown = (e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
login(); login()
} }
}; }
return ( return (
<LoginWrapper> <LoginWrapper>
{modalContext} { modalContext }
<div className="app-title"> <div className="app-title">
<span>Databag</span> <span>Databag</span>
<div <div className="settings" onClick={() => actions.onSettings()}>
className="settings"
onClick={() => actions.onSettings()}
>
<SettingOutlined /> <SettingOutlined />
</div> </div>
</div> </div>
<div className="form-title"> <div className="form-title">
<div>{state.strings.login}</div> <div>{ state.strings.login }</div>
{!state.available && state.availableSet && <div className="form-message">{state.strings.toCreate}</div>} { !state.available && state.availableSet && (
<div className="form-message">{ state.strings.toCreate }</div>
)}
</div> </div>
<div className="form-form"> <div className="form-form">
<Form <Form name="basic" wrapperCol={{ span: 24, }}>
name="basic"
wrapperCol={{ span: 24 }}
>
<Form.Item name="username"> <Form.Item name="username">
<Input <Input placeholder={state.strings.username} spellCheck="false" onChange={(e) => actions.setUsername(e.target.value)}
placeholder={state.strings.username} autoComplete="username" autoCapitalize="none" onKeyDown={(e) => keyDown(e)} prefix={<UserOutlined />} size="large" />
spellCheck="false"
onChange={(e) => actions.setUsername(e.target.value)}
autoComplete="username"
autoCapitalize="none"
onKeyDown={(e) => keyDown(e)}
prefix={<UserOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<Form.Item name="password"> <Form.Item name="password">
<Input.Password <Input.Password placeholder={state.strings.password} spellCheck="false" onChange={(e) => actions.setPassword(e.target.value)}
placeholder={state.strings.password} autoComplete="current-password" onKeyDown={(e) => keyDown(e)} prefix={<LockOutlined />} size="large" />
spellCheck="false"
onChange={(e) => actions.setPassword(e.target.value)}
autoComplete="current-password"
onKeyDown={(e) => keyDown(e)}
prefix={<LockOutlined />}
size="large"
/>
</Form.Item> </Form.Item>
<div className="form-button"> <div className="form-button">
<div className="form-login"> <div className="form-login">
<Button <Button className={actions.isDisabled() ? 'disabled' : 'enabled'} type="primary" block onClick={login} disabled={ actions.isDisabled()}
className={actions.isDisabled() ? 'disabled' : 'enabled'} size="middle" loading={state.busy}>
type="primary"
block
onClick={login}
disabled={actions.isDisabled()}
size="middle"
loading={state.busy}
>
{state.strings.login} {state.strings.login}
</Button> </Button>
</div> </div>
</div> </div>
<div className="form-button"> <div className="form-button">
<Button <Button type="link" block disabled={ !state.available } onClick={(e) => actions.onCreate()}>
type="link"
block
disabled={!state.available}
onClick={(e) => actions.onCreate()}
>
{state.strings.createAccount} {state.strings.createAccount}
</Button> </Button>
</div> </div>
</Form> </Form>
</div> </div>
</LoginWrapper> </LoginWrapper>
); );
} };

View File

@ -2,9 +2,10 @@ import { useContext, useState, useEffect } from 'react';
import { AppContext } from 'context/AppContext'; import { AppContext } from 'context/AppContext';
import { SettingsContext } from 'context/SettingsContext'; import { SettingsContext } from 'context/SettingsContext';
import { getAvailable } from 'api/getAvailable'; import { getAvailable } from 'api/getAvailable';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from "react-router-dom";
export function useLogin() { export function useLogin() {
const [state, setState] = useState({ const [state, setState] = useState({
username: '', username: '',
password: '', password: '',
@ -12,7 +13,7 @@ export function useLogin() {
availableSet: false, availableSet: false,
disabled: true, disabled: true,
busy: false, busy: false,
strings: {} as Record<string, string>, strings: {} as Record<string,string>,
menuStyle: {}, menuStyle: {},
}); });
@ -23,7 +24,7 @@ export function useLogin() {
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
}; }
const actions = { const actions = {
setUsername: (username) => { setUsername: (username) => {
@ -34,24 +35,25 @@ export function useLogin() {
}, },
isDisabled: () => { isDisabled: () => {
if (state.username === '' || state.password === '') { if (state.username === '' || state.password === '') {
return true; return true
} }
return false; return false
}, },
onSettings: () => { onSettings: () => {
navigate('/admin'); navigate('/admin');
}, },
onLogin: async () => { onLogin: async () => {
if (!state.busy && state.username !== '' && state.password !== '') { if (!state.busy && state.username !== '' && state.password !== '') {
updateState({ busy: true }); updateState({ busy: true })
try { try {
await app.actions.login(state.username, state.password); await app.actions.login(state.username, state.password)
} catch (err) { }
catch (err) {
console.log(err); console.log(err);
updateState({ busy: false }); updateState({ busy: false })
throw new Error('login failed: check your username and password'); throw new Error('login failed: check your username and password');
} }
updateState({ busy: false }); updateState({ busy: false })
} }
}, },
onCreate: () => { onCreate: () => {
@ -62,43 +64,46 @@ export function useLogin() {
useEffect(() => { useEffect(() => {
const count = async () => { const count = async () => {
try { try {
const available = await getAvailable(); const available = await getAvailable()
updateState({ availableSet: true, available: available !== 0 }); updateState({ availableSet: true, available: available !== 0 })
} catch (err) { }
catch(err) {
console.log(err); console.log(err);
} }
}; }
count(); count();
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, [])
useEffect(() => { useEffect(() => {
const { strings, menuStyle } = settings.state; const { strings, menuStyle } = settings.state;
updateState({ strings, menuStyle }); updateState({ strings, menuStyle });
}, [settings.state]); }, [settings.state]);
const access = async (token) => { const access = async (token) => {
if (!state.busy) { if (!state.busy) {
updateState({ busy: true }); updateState({ busy: true });
try { try {
await app.actions.access(token); await app.actions.access(token);
} catch (err) { }
catch (err) {
console.log(err); console.log(err);
updateState({ busy: false }); updateState({ busy: false });
throw new Error('access failed: check your token'); throw new Error('access failed: check your token');
} }
updateState({ busy: false }); updateState({ busy: false });
} }
}; }
useEffect(() => { useEffect(() => {
let params = new URLSearchParams(search); let params = new URLSearchParams(search);
let token = params.get('access'); let token = params.get("access");
if (token) { if (token) {
access(token); access(token);
} }
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, [])
return { state, actions }; return { state, actions };
} }

View File

@ -1,9 +1,10 @@
import { useContext, useState, useEffect } from 'react'; import { useContext, useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from "react-router-dom";
import { AppContext } from 'context/AppContext'; import { AppContext } from 'context/AppContext';
import { SettingsContext } from 'context/SettingsContext'; import { SettingsContext } from 'context/SettingsContext';
export function useAccess() { export function useAccess() {
const [state, setState] = useState({ const [state, setState] = useState({
display: null, display: null,
scheme: null, scheme: null,
@ -12,7 +13,7 @@ export function useAccess() {
themes: [], themes: [],
language: null, language: null,
languages: [], languages: [],
strings: {} as Record<string, string>, strings: {} as Record<string,string>,
}); });
const navigate = useNavigate(); const navigate = useNavigate();
@ -22,7 +23,7 @@ export function useAccess() {
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
}; }
useEffect(() => { useEffect(() => {
if (app.state.status || app.state.adminToken) { if (app.state.status || app.state.adminToken) {
@ -31,21 +32,23 @@ export function useAccess() {
}, [app.state, navigate]); }, [app.state, navigate]);
useEffect(() => { useEffect(() => {
let params = new URLSearchParams(location + ''); let params = new URLSearchParams(location+"");
let token = params.get('access'); let token = params.get("access");
if (token) { if (token) {
const access = async () => { const access = async () => {
try { try {
await app.actions.access(token); await app.actions.access(token)
} catch (err) { }
catch (err) {
console.log(err); console.log(err);
} }
}; }
access(); access();
} }
// eslint-disable-next-line // eslint-disable-next-line
}, [navigate, location]); }, [navigate, location]);
useEffect(() => { useEffect(() => {
const { theme, themes, strings, language, languages, colors, display, scheme } = settings.state; const { theme, themes, strings, language, languages, colors, display, scheme } = settings.state;
updateState({ theme, themes, language, languages, strings, colors, display, scheme }); updateState({ theme, themes, language, languages, strings, colors, display, scheme });
@ -62,3 +65,4 @@ export function useAccess() {
return { state, actions }; return { state, actions };
} }

View File

@ -2,13 +2,14 @@ import { checkResponse, fetchWithCustomTimeout } from './fetchUtil';
var base64 = require('base-64'); var base64 = require('base-64');
export async function addAccount(username, password, token) { export async function addAccount(username, password, token) {
let access = ''; let access = "";
if (token) { if (token) {
access = `?token=${token}`; access = `?token=${token}`
} }
let headers = new Headers(); let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ':' + password)); headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let profile = await fetchWithCustomTimeout(`/account/profile${access}`, { method: 'POST', headers: headers }, 60000); let profile = await fetchWithCustomTimeout(`/account/profile${access}`, { method: 'POST', headers: headers }, 60000)
checkResponse(profile); checkResponse(profile);
return await profile.json(); return await profile.json()
} }

View File

@ -1,9 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addAccountAccess(token, accountId) { export async function addAccountAccess(token, accountId) {
let access = await fetchWithTimeout(`/admin/accounts/${accountId}/auth?token=${encodeURIComponent(token)}`, { let access = await fetchWithTimeout(`/admin/accounts/${accountId}/auth?token=${encodeURIComponent(token)}`, { method: 'POST' })
method: 'POST',
});
checkResponse(access); checkResponse(access);
return await access.json(); return await access.json()
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addAccountCreate(token) { export async function addAccountCreate(token) {
let access = await fetchWithTimeout(`/admin/accounts?token=${encodeURIComponent(token)}`, { method: 'POST' }); let access = await fetchWithTimeout(`/admin/accounts?token=${encodeURIComponent(token)}`, { method: 'POST' })
checkResponse(access); checkResponse(access);
return await access.json(); return await access.json()
} }

View File

@ -1,9 +1,10 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addCall(token, cardId) { export async function addCall(token, cardId) {
let param = '?agent=' + token; let param = "?agent=" + token
let call = await fetchWithTimeout('/talk/calls' + param, { method: 'POST', body: JSON.stringify(cardId) }); let call = await fetchWithTimeout('/talk/calls' + param, { method: 'POST', body: JSON.stringify(cardId) });
checkResponse(call); checkResponse(call)
let ret = await call.json(); let ret = await call.json()
return ret; return ret;
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addCard(token, message) { export async function addCard(token, message) {
let card = await fetchWithTimeout(`/contact/cards?agent=${token}`, { method: 'POST', body: JSON.stringify(message) }); let card = await fetchWithTimeout(`/contact/cards?agent=${token}`, { method: 'POST', body: JSON.stringify(message)} );
checkResponse(card); checkResponse(card);
return await card.json(); return await card.json();
} }

View File

@ -1,11 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addChannel(token, type, cards, data) { export async function addChannel(token, type, cards, data ) {
let params = { dataType: type, data: JSON.stringify(data), groups: [], cards }; let params = { dataType: type, data: JSON.stringify(data), groups: [], cards };
let channel = await fetchWithTimeout(`/content/channels?agent=${token}`, { let channel = await fetchWithTimeout(`/content/channels?agent=${token}`, { method: 'POST', body: JSON.stringify(params)} );
method: 'POST',
body: JSON.stringify(params),
});
checkResponse(channel); checkResponse(channel);
return await channel.json(); return await channel.json();
} }

View File

@ -1,34 +1,29 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addChannelTopic(token, channelId, datatype, message, assets) { export async function addChannelTopic(token, channelId, datatype, message, assets ) {
if (message == null && (assets == null || assets.length === 0)) {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`, {
method: 'POST',
body: JSON.stringify({}),
});
checkResponse(topic);
let slot = await topic.json();
return slot.id;
} else if (assets == null || assets.length === 0) {
let subject = {
data: JSON.stringify(message, (key, value) => {
if (value !== null) return value;
}),
datatype,
};
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}&confirm=true`, { if (message == null && (assets == null || assets.length === 0)) {
method: 'POST', let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
body: JSON.stringify(subject), { method: 'POST', body: JSON.stringify({}) });
});
checkResponse(topic); checkResponse(topic);
let slot = await topic.json(); let slot = await topic.json();
return slot.id; return slot.id;
} else { }
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`, { else if (assets == null || assets.length === 0) {
method: 'POST', let subject = { data: JSON.stringify(message, (key, value) => {
body: JSON.stringify({}), if (value !== null) return value
}); }), datatype };
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}&confirm=true`,
{ method: 'POST', body: JSON.stringify(subject) });
checkResponse(topic);
let slot = await topic.json();
return slot.id;
}
else {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
{ method: 'POST', body: JSON.stringify({}) });
checkResponse(topic); checkResponse(topic);
let slot = await topic.json(); let slot = await topic.json();
@ -38,74 +33,61 @@ export async function addChannelTopic(token, channelId, datatype, message, asset
if (asset.image) { if (asset.image) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.image); formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(['ithumb;photo', 'icopy;photo'])); let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
image: { image: {
thumb: assetEntry.find((item) => item.transform === 'ithumb;photo').assetId, thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find((item) => item.transform === 'icopy;photo').assetId, full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}, }
}); });
} else if (asset.video) { }
else if (asset.video) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.video); formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position; let thumb = 'vthumb;video;' + asset.position;
let transform = encodeURIComponent(JSON.stringify(['vlq;video', 'vhd;video', thumb])); let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", thumb]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
video: { video: {
thumb: assetEntry.find((item) => item.transform === thumb).assetId, thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find((item) => item.transform === 'vlq;video').assetId, lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find((item) => item.transform === 'vhd;video').assetId, hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}, }
}); });
} else if (asset.audio) { }
else if (asset.audio) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.audio); formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(['acopy;audio'])); let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
audio: { audio: {
label: asset.label, label: asset.label,
full: assetEntry.find((item) => item.transform === 'acopy;audio').assetId, full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}, }
}); });
} }
} }
let subject = { let subject = { data: JSON.stringify(message, (key, value) => {
data: JSON.stringify(message, (key, value) => { if (value !== null) return value
if (value !== null) return value; }), datatype };
}),
datatype,
};
let unconfirmed = await fetchWithTimeout( let unconfirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`,
`/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`, { method: 'PUT', body: JSON.stringify(subject) });
{ method: 'PUT', body: JSON.stringify(subject) },
);
checkResponse(unconfirmed); checkResponse(unconfirmed);
let confirmed = await fetchWithTimeout( let confirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/confirmed?agent=${token}`,
`/content/channels/${channelId}/topics/${slot.id}/confirmed?agent=${token}`, { method: 'PUT', body: JSON.stringify('confirmed') });
{ method: 'PUT', body: JSON.stringify('confirmed') },
);
checkResponse(confirmed); checkResponse(confirmed);
return slot.id; return slot.id;
} }
} }

View File

@ -1,39 +1,32 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addContactChannelTopic(server, token, channelId, datatype, message, assets) { export async function addContactChannelTopic(server, token, channelId, datatype, message, assets ) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`
} }
if (message == null && (assets == null || assets.length === 0)) { if (message == null && (assets == null || assets.length === 0)) {
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`, { let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`,
method: 'POST', { method: 'POST', body: JSON.stringify({}) });
body: JSON.stringify({}),
});
checkResponse(topic); checkResponse(topic);
let slot = await topic.json(); let slot = await topic.json();
return slot.id; return slot.id;
} else if (assets == null || assets.length === 0) { }
let subject = { else if (assets == null || assets.length === 0) {
data: JSON.stringify(message, (key, value) => { let subject = { data: JSON.stringify(message, (key, value) => {
if (value !== null) return value; if (value !== null) return value
}), }), datatype };
datatype,
};
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}&confirm=true`, { let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}&confirm=true`,
method: 'POST', { method: 'POST', body: JSON.stringify(subject) });
body: JSON.stringify(subject),
});
checkResponse(topic); checkResponse(topic);
let slot = await topic.json(); let slot = await topic.json();
return slot.id; return slot.id;
} else { }
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`, { else {
method: 'POST', let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`,
body: JSON.stringify({}), { method: 'POST', body: JSON.stringify({}) });
});
checkResponse(topic); checkResponse(topic);
let slot = await topic.json(); let slot = await topic.json();
@ -43,74 +36,61 @@ export async function addContactChannelTopic(server, token, channelId, datatype,
if (asset.image) { if (asset.image) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.image); formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(['ithumb;photo', 'icopy;photo'])); let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
image: { image: {
thumb: assetEntry.find((item) => item.transform === 'ithumb;photo').assetId, thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find((item) => item.transform === 'icopy;photo').assetId, full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}, }
}); });
} else if (asset.video) { }
else if (asset.video) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.video); formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position; let thumb = "vthumb;video;" + asset.position
let transform = encodeURIComponent(JSON.stringify(['vhd;video', 'vlq;video', thumb])); let transform = encodeURIComponent(JSON.stringify(["vhd;video", "vlq;video", thumb]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
video: { video: {
thumb: assetEntry.find((item) => item.transform === thumb).assetId, thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find((item) => item.transform === 'vlq;video').assetId, lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find((item) => item.transform === 'vhd;video').assetId, hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}, }
}); });
} else if (asset.audio) { }
else if (asset.audio) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.audio); formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(['acopy;audio'])); let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
message.assets.push({ message.assets.push({
audio: { audio: {
label: asset.label, label: asset.label,
full: assetEntry.find((item) => item.transform === 'acopy;audio').assetId, full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}, }
}); });
} }
} }
let subject = { let subject = { data: JSON.stringify(message, (key, value) => {
data: JSON.stringify(message, (key, value) => { if (value !== null) return value
if (value !== null) return value; }), datatype };
}),
datatype,
};
let unconfirmed = await fetchWithTimeout( let unconfirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`,
`${host}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`, { method: 'PUT', body: JSON.stringify(subject) });
{ method: 'PUT', body: JSON.stringify(subject) },
);
checkResponse(unconfirmed); checkResponse(unconfirmed);
let confirmed = await fetchWithTimeout( let confirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/confirmed?contact=${token}`,
`${host}/content/channels/${channelId}/topics/${slot.id}/confirmed?contact=${token}`, { method: 'PUT', body: JSON.stringify('confirmed') });
{ method: 'PUT', body: JSON.stringify('confirmed') },
);
checkResponse(confirmed); checkResponse(confirmed);
return slot.id; return slot.id;
} }
} }

View File

@ -1,14 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addContactRing(server, token, call) { export async function addContactRing(server, token, call) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`
} }
let ring = await fetchWithTimeout(`${host}/talk/rings?contact=${token}`, { let ring = await fetchWithTimeout(`${host}/talk/rings?contact=${token}`, { method: 'POST', body: JSON.stringify(call) });
method: 'POST',
body: JSON.stringify(call),
});
checkResponse(ring); checkResponse(ring);
} }

View File

@ -1,9 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function clearChannelCard(token, channelId, cardId) { export async function clearChannelCard(token, channelId, cardId ) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, { let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'DELETE'});
method: 'DELETE',
});
checkResponse(channel); checkResponse(channel);
return await channel.json(); return await channel.json();
} }

View File

@ -1,9 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function clearLogin(token, all) { export async function clearLogin(token, all) {
console.log('LOGOUT: ', token, all); console.log("LOGOUT: ", token, all);
const param = all ? '&all=true' : ''; const param = all ? '&all=true' : ''
const logout = await fetchWithTimeout(`/account/apps?agent=${token}${param}`, { method: 'DELETE' }); const logout = await fetchWithTimeout(`/account/apps?agent=${token}${param}`, { method: 'DELETE' })
checkResponse(logout); checkResponse(logout)
} }

View File

@ -2,9 +2,10 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
var base64 = require('base-64'); var base64 = require('base-64');
export async function createAccount(username, password) { export async function createAccount(username, password) {
let headers = new Headers(); let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ':' + password)); headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let profile = await fetchWithTimeout('/account/profile', { method: 'POST', headers: headers }); let profile = await fetchWithTimeout("/account/profile", { method: 'POST', headers: headers })
checkResponse(profile); checkResponse(profile);
return await profile.json(); return await profile.json()
} }

View File

@ -7,25 +7,22 @@ export function createWebsocket(url) {
} }
export function checkResponse(response) { export function checkResponse(response) {
if (response.status >= 400 && response.status < 600) { if(response.status >= 400 && response.status < 600) {
throw new Error(response.url + ' failed'); throw new Error(response.url + " failed");
} }
} }
export async function fetchWithTimeout(url, options): Promise<Response> { export async function fetchWithTimeout(url, options):Promise<Response> {
return Promise.race([ return Promise.race([
fetch(url, options).catch((err) => { fetch(url, options).catch(err => { throw new Error(url + ' failed'); }),
throw new Error(url + ' failed'); new Promise<Response>((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), TIMEOUT))
}),
new Promise<Response>((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), TIMEOUT)),
]); ]);
} }
export async function fetchWithCustomTimeout(url, options, timeout): Promise<Response> { export async function fetchWithCustomTimeout(url, options, timeout):Promise<Response> {
return Promise.race([ return Promise.race([
fetch(url, options).catch((err) => { fetch(url, options).catch(err => { throw new Error(url + ' failed'); }),
throw new Error(url + ' failed'); new Promise<Response>((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), timeout))
}),
new Promise<Response>((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), timeout)),
]); ]);
} }

View File

@ -1,3 +1,4 @@
export function getAccountImageUrl(token, accountId) { export function getAccountImageUrl(token, accountId) {
return `/admin/accounts/${accountId}/image?token=${encodeURIComponent(token)}`; return `/admin/accounts/${accountId}/image?token=${encodeURIComponent(token)}`
} }

View File

@ -3,5 +3,6 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getAccountStatus(token) { export async function getAccountStatus(token) {
let status = await fetchWithTimeout('/account/status?agent=' + token, { method: 'GET' }); let status = await fetchWithTimeout('/account/status?agent=' + token, { method: 'GET' });
checkResponse(status); checkResponse(status);
return await status.json(); return await status.json()
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getAvailable() { export async function getAvailable() {
let available = await fetchWithTimeout('/account/available', { method: 'GET' }); let available = await fetchWithTimeout("/account/available", { method: 'GET' })
checkResponse(available); checkResponse(available)
return await available.json(); return await available.json()
} }

View File

@ -5,3 +5,4 @@ export async function getCardCloseMessage(token, cardId) {
checkResponse(message); checkResponse(message);
return await message.json(); return await message.json();
} }

View File

@ -1,8 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardDetail(token, cardId) { export async function getCardDetail(token, cardId) {
let param = '?agent=' + token; let param = "?agent=" + token
let detail = await fetchWithTimeout(`/contact/cards/${cardId}/detail${param}`, { method: 'GET' }); let detail = await fetchWithTimeout(`/contact/cards/${cardId}/detail${param}`, { method: 'GET' });
checkResponse(detail); checkResponse(detail);
return await detail.json(); return await detail.json()
} }

View File

@ -1,3 +1,4 @@
export function getCardImageUrl(token, cardId, revision) { export function getCardImageUrl(token, cardId, revision) {
return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`; return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
} }

View File

@ -5,3 +5,4 @@ export async function getCardOpenMessage(token, cardId) {
checkResponse(message); checkResponse(message);
return await message.json(); return await message.json();
} }

View File

@ -3,5 +3,6 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardProfile(token, cardId) { export async function getCardProfile(token, cardId) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'GET' }); let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'GET' });
checkResponse(profile); checkResponse(profile);
return await profile.json(); return await profile.json()
} }

View File

@ -1,11 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCards(token, revision) { export async function getCards(token, revision) {
let param = 'agent=' + token; let param = "agent=" + token
if (revision != null) { if (revision != null) {
param += '&revision=' + revision; param += '&revision=' + revision
} }
let cards = await fetchWithTimeout(`/contact/cards?${param}`, { method: 'GET' }); let cards = await fetchWithTimeout(`/contact/cards?${param}`, { method: 'GET' });
checkResponse(cards); checkResponse(cards)
return await cards.json(); return await cards.json()
} }

View File

@ -2,6 +2,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelDetail(token, channelId) { export async function getChannelDetail(token, channelId) {
let detail = await fetchWithTimeout(`/content/channels/${channelId}/detail?agent=${token}`, { method: 'GET' }); let detail = await fetchWithTimeout(`/content/channels/${channelId}/detail?agent=${token}`, { method: 'GET' });
checkResponse(detail); checkResponse(detail)
return await detail.json(); return await detail.json()
} }

View File

@ -2,6 +2,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelSummary(token, channelId) { export async function getChannelSummary(token, channelId) {
let summary = await fetchWithTimeout(`/content/channels/${channelId}/summary?agent=${token}`, { method: 'GET' }); let summary = await fetchWithTimeout(`/content/channels/${channelId}/summary?agent=${token}`, { method: 'GET' });
checkResponse(summary); checkResponse(summary)
return await summary.json(); return await summary.json()
} }

View File

@ -1,9 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelTopic(token, channelId, topicId) { export async function getChannelTopic(token, channelId, topicId) {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}/detail?agent=${token}`, { let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}/detail?agent=${token}`,
method: 'GET', { method: 'GET' });
}); checkResponse(topic)
checkResponse(topic); return await topic.json()
return await topic.json();
} }

View File

@ -1,3 +1,4 @@
export function getChannelTopicAssetUrl(token, channelId, topicId, assetId) { export function getChannelTopicAssetUrl(token, channelId, topicId, assetId) {
return `/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?agent=${token}`; return `/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?agent=${token}`
} }

View File

@ -1,29 +1,29 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelTopics(token, channelId, revision, count, begin, end) { export async function getChannelTopics(token, channelId, revision, count, begin, end) {
let rev = ''; let rev = ''
if (revision != null) { if (revision != null) {
rev = `&revision=${revision}`; rev = `&revision=${revision}`
} }
let cnt = ''; let cnt = ''
if (count != null) { if (count != null) {
cnt = `&count=${count}`; cnt = `&count=${count}`
} }
let bgn = ''; let bgn = ''
if (begin != null) { if (begin != null) {
bgn = `&begin=${begin}`; bgn = `&begin=${begin}`
} }
let edn = ''; let edn = ''
if (end != null) { if (end != null) {
edn = `&end=${end}`; edn = `&end=${end}`
} }
let topics = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}${rev}${cnt}${bgn}${edn}`, { let topics = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}${rev}${cnt}${bgn}${edn}`,
method: 'GET', { method: 'GET' });
}); checkResponse(topics)
checkResponse(topics);
return { return {
marker: topics.headers.get('topic-marker'), marker: topics.headers.get('topic-marker'),
revision: topics.headers.get('topic-revision'), revision: topics.headers.get('topic-revision'),
topics: await topics.json(), topics: await topics.json(),
}; }
} }

View File

@ -1,14 +1,15 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannels(token, revision) { export async function getChannels(token, revision) {
let param = '?agent=' + token; let param = "?agent=" + token
if (revision != null) { if (revision != null) {
param += `&channelRevision=${revision}`; param += `&channelRevision=${revision}`
} }
let types = encodeURIComponent(JSON.stringify(['sealed', 'superbasic'])); let types = encodeURIComponent(JSON.stringify([ 'sealed', 'superbasic' ]));
param += `&types=${types}`; param += `&types=${types}`
let channels = await fetchWithTimeout('/content/channels' + param, { method: 'GET' }); let channels = await fetchWithTimeout('/content/channels' + param, { method: 'GET' });
checkResponse(channels); checkResponse(channels)
let ret = await channels.json(); let ret = await channels.json()
return ret; return ret;
} }

View File

@ -1,13 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelDetail(server, token, channelId) { export async function getContactChannelDetail(server, token, channelId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let detail = await fetchWithTimeout(`${host}/content/channels/${channelId}/detail?contact=${token}`, { let detail = await fetchWithTimeout(`${host}/content/channels/${channelId}/detail?contact=${token}`, { method: 'GET' });
method: 'GET', checkResponse(detail)
}); return await detail.json()
checkResponse(detail);
return await detail.json();
} }

View File

@ -1,13 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelSummary(server, token, channelId) { export async function getContactChannelSummary(server, token, channelId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let summary = await fetchWithTimeout(`${host}/content/channels/${channelId}/summary?contact=${token}`, { let summary = await fetchWithTimeout(`${host}/content/channels/${channelId}/summary?contact=${token}`, { method: 'GET' });
method: 'GET', checkResponse(summary)
}); return await summary.json()
checkResponse(summary);
return await summary.json();
} }

View File

@ -1,15 +1,14 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelTopic(server, token, channelId, topicId) { export async function getContactChannelTopic(server, token, channelId, topicId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let topic = await fetchWithTimeout( let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/detail?contact=${token}`,
`${host}/content/channels/${channelId}/topics/${topicId}/detail?contact=${token}`, { method: 'GET' });
{ method: 'GET' }, checkResponse(topic)
); return await topic.json()
checkResponse(topic);
return await topic.json();
} }

View File

@ -1,8 +1,9 @@
export function getContactChannelTopicAssetUrl(server, token, channelId, topicId, assetId) { export function getContactChannelTopicAssetUrl(server, token, channelId, topicId, assetId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
return `${host}/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?contact=${token}`; return `${host}/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?contact=${token}`
} }

View File

@ -1,35 +1,34 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelTopics(server, token, channelId, revision, count, begin, end) { export async function getContactChannelTopics(server, token, channelId, revision, count, begin, end) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let rev = ''; let rev = ''
if (revision != null) { if (revision != null) {
rev = `&revision=${revision}`; rev = `&revision=${revision}`
} }
let cnt = ''; let cnt = ''
if (count != null) { if (count != null) {
cnt = `&count=${count}`; cnt = `&count=${count}`
} }
let bgn = ''; let bgn = ''
if (begin != null) { if (begin != null) {
bgn = `&begin=${begin}`; bgn = `&begin=${begin}`
} }
let edn = ''; let edn = ''
if (end != null) { if (end != null) {
edn = `&end=${end}`; edn = `&end=${end}`
} }
let topics = await fetchWithTimeout( let topics = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}${rev}${cnt}${bgn}${edn}`,
`${host}/content/channels/${channelId}/topics?contact=${token}${rev}${cnt}${bgn}${edn}`, { method: 'GET' });
{ method: 'GET' }, checkResponse(topics)
);
checkResponse(topics);
return { return {
marker: topics.headers.get('topic-marker'), marker: topics.headers.get('topic-marker'),
revision: topics.headers.get('topic-revision'), revision: topics.headers.get('topic-revision'),
topics: await topics.json(), topics: await topics.json(),
}; }
} }

View File

@ -1,21 +1,22 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannels(server, token, viewRevision?, channelRevision?) { export async function getContactChannels(server, token, viewRevision?, channelRevision?) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let param = '?contact=' + token; let param = "?contact=" + token
if (viewRevision != null) { if (viewRevision != null) {
param += '&viewRevision=' + viewRevision; param += '&viewRevision=' + viewRevision
} }
if (channelRevision != null) { if (channelRevision != null) {
param += '&channelRevision=' + channelRevision; param += '&channelRevision=' + channelRevision
} }
let types = encodeURIComponent(JSON.stringify(['sealed', 'superbasic'])); let types = encodeURIComponent(JSON.stringify([ 'sealed', 'superbasic' ]));
param += `&types=${types}`; param += `&types=${types}`
let channels = await fetchWithTimeout(`${host}/content/channels${param}`, { method: 'GET' }); let channels = await fetchWithTimeout(`${host}/content/channels${param}`, { method: 'GET' });
checkResponse(channels); checkResponse(channels)
return await channels.json(); return await channels.json()
} }

View File

@ -1,12 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactProfile(server, token) { export async function getContactProfile(server, token) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let profile = await fetchWithTimeout(`${host}/profile/message?contact=${token}`, { method: 'GET' }); let profile = await fetchWithTimeout(`${host}/profile/message?contact=${token}`, { method: 'GET', });
checkResponse(profile); checkResponse(profile);
return await profile.json(); return await profile.json()
} }

View File

@ -1,11 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getGroups(token, revision) { export async function getGroups(token, revision) {
let param = 'agent=' + token; let param = "agent=" + token
if (revision != null) { if (revision != null) {
param += '&revision=' + revision; param += '&revision=' + revision
} }
let groups = await fetchWithTimeout(`/alias/groups?${param}`, { method: 'GET' }); let groups = await fetchWithTimeout(`/alias/groups?${param}`, { method: 'GET' });
checkResponse(groups); checkResponse(groups)
return await groups.json(); return await groups.json()
} }

View File

@ -8,3 +8,4 @@ export async function getListing(server, filter) {
checkResponse(listing); checkResponse(listing);
return await listing.json(); return await listing.json();
} }

View File

@ -1,8 +1,10 @@
export function getListingImageUrl(server, guid) { export function getListingImageUrl(server, guid) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
return `${host}/account/listing/${guid}/image`; return `${host}/account/listing/${guid}/image`
} }

View File

@ -1,7 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getListingMessage(server, guid) { export async function getListingMessage(server, guid) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
@ -10,3 +10,4 @@ export async function getListingMessage(server, guid) {
checkResponse(listing); checkResponse(listing);
return await listing.json(); return await listing.json();
} }

View File

@ -5,3 +5,4 @@ export async function getNodeAccounts(token) {
checkResponse(accounts); checkResponse(accounts);
return await accounts.json(); return await accounts.json();
} }

View File

@ -5,3 +5,4 @@ export async function getNodeConfig(token) {
checkResponse(config); checkResponse(config);
return await config.json(); return await config.json();
} }

View File

@ -5,3 +5,4 @@ export async function getNodeStatus() {
checkResponse(status); checkResponse(status);
return await status.json(); return await status.json();
} }

View File

@ -2,6 +2,8 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getProfile(token) { export async function getProfile(token) {
let profile = await fetchWithTimeout(`/profile?agent=${token}`, { method: 'GET' }); let profile = await fetchWithTimeout(`/profile?agent=${token}`, { method: 'GET' });
checkResponse(profile); checkResponse(profile)
return await profile.json(); return await profile.json()
} }

View File

@ -1,3 +1,4 @@
export function getProfileImageUrl(token, revision) { export function getProfileImageUrl(token, revision) {
return '/profile/image?agent=' + token + '&revision=' + revision; return '/profile/image?agent=' + token + "&revision=" + revision
} }

View File

@ -1,13 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getUsername(name, token) { export async function getUsername(name, token) {
let access = ''; let access = "";
if (token) { if (token) {
access = `&token=${token}`; access = `&token=${token}`
} }
let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name) + access, { let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name) + access, { method: 'GET' })
method: 'GET', checkResponse(available)
}); return await available.json()
checkResponse(available);
return await available.json();
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function keepCall(token, callId) { export async function keepCall(token, callId) {
let param = '?agent=' + token; let param = "?agent=" + token
let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'PUT' }); let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'PUT' });
checkResponse(call); checkResponse(call)
} }

View File

@ -1,8 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeAccount(token, accountId) { export async function removeAccount(token, accountId) {
let res = await fetchWithTimeout(`/admin/accounts/${accountId}?token=${encodeURIComponent(token)}`, { let res = await fetchWithTimeout(`/admin/accounts/${accountId}?token=${encodeURIComponent(token)}`, { method: 'DELETE' })
method: 'DELETE',
});
checkResponse(res); checkResponse(res);
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeCall(token, callId) { export async function removeCall(token, callId) {
let param = '?agent=' + token; let param = "?agent=" + token
let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'DELETE' }); let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'DELETE' });
checkResponse(call); checkResponse(call)
} }

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeCard(token, cardId) { export async function removeCard(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}?agent=${token}`, { method: 'DELETE' }); let card = await fetchWithTimeout(`/contact/cards/${cardId}?agent=${token}`, { method: 'DELETE' } );
checkResponse(card); checkResponse(card);
return await card.json(); return await card.json();
} }

View File

@ -1,6 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeChannel(token, channelId) { export async function removeChannel(token, channelId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}?agent=${token}`, { method: 'DELETE' });
let channel = await fetchWithTimeout(`/content/channels/${channelId}?agent=${token}`,
{ method: 'DELETE' });
checkResponse(channel); checkResponse(channel);
} }

View File

@ -1,8 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeChannelTopic(token, channelId, topicId) { export async function removeChannelTopic(token, channelId, topicId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}?agent=${token}`, {
method: 'DELETE', let channel = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}?agent=${token}`,
}); { method: 'DELETE' });
checkResponse(channel); checkResponse(channel);
} }

View File

@ -1,11 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactCall(server, token, callId) { export async function removeContactCall(server, token, callId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`
} }
const call = await fetchWithTimeout(`${host}/talk/calls/${callId}?contact=${token}`, { method: 'DELETE' }); const call = await fetchWithTimeout(`${host}/talk/calls/${callId}?contact=${token}`, { method: 'DELETE' });
checkResponse(call); checkResponse(call);
} }

View File

@ -1,11 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactChannel(server, token, channelId) { export async function removeContactChannel(server, token, channelId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}?contact=${token}`, { method: 'DELETE' }); let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}?contact=${token}`,
{ method: 'DELETE' });
checkResponse(channel); checkResponse(channel);
} }

View File

@ -1,13 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactChannelTopic(server, token, channelId, topicId) { export async function removeContactChannelTopic(server, token, channelId, topicId) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}?contact=${token}`, { let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}?contact=${token}`,
method: 'DELETE', { method: 'DELETE' });
});
checkResponse(channel); checkResponse(channel);
} }

View File

@ -1,10 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountAccess(token, appName, appVersion, platform) { export async function setAccountAccess(token, appName, appVersion, platform) {
let access = await fetchWithTimeout( let access = await fetchWithTimeout(`/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'PUT', body: JSON.stringify([]) })
`/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}`, checkResponse(access)
{ method: 'PUT', body: JSON.stringify([]) }, return await access.json()
);
checkResponse(access);
return await access.json();
} }

View File

@ -2,8 +2,9 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
var base64 = require('base-64'); var base64 = require('base-64');
export async function setAccountLogin(token, username, password) { export async function setAccountLogin(token, username, password) {
let headers = new Headers(); let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ':' + password)); headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let res = await fetchWithTimeout(`/account/login?agent=${token}`, { method: 'PUT', headers }); let res = await fetchWithTimeout(`/account/login?agent=${token}`, { method: 'PUT', headers })
checkResponse(res); checkResponse(res);
} }

View File

@ -1,6 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountSeal(token, seal) { export async function setAccountSeal(token, seal) {
let res = await fetchWithTimeout('/account/seal?agent=' + token, { method: 'PUT', body: JSON.stringify(seal) }); let res = await fetchWithTimeout('/account/seal?agent=' + token, { method: 'PUT', body: JSON.stringify(seal) })
checkResponse(res); checkResponse(res);
} }

View File

@ -1,6 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountSearchable(token, flag) { export async function setAccountSearchable(token, flag) {
let res = await fetchWithTimeout('/account/searchable?agent=' + token, { method: 'PUT', body: JSON.stringify(flag) }); let res = await fetchWithTimeout('/account/searchable?agent=' + token, { method: 'PUT', body: JSON.stringify(flag) })
checkResponse(res); checkResponse(res);
} }

View File

@ -1,9 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountStatus(token, accountId, disabled) { export async function setAccountStatus(token, accountId, disabled) {
let res = await fetchWithTimeout(`/admin/accounts/${accountId}/status?token=${encodeURIComponent(token)}`, { let res = await fetchWithTimeout(`/admin/accounts/${accountId}/status?token=${encodeURIComponent(token)}`, { method: 'PUT', body: JSON.stringify(disabled) })
method: 'PUT',
body: JSON.stringify(disabled),
});
checkResponse(res); checkResponse(res);
} }

View File

@ -1,7 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardCloseMessage(server, message) { export async function setCardCloseMessage(server, message) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
@ -10,3 +10,4 @@ export async function setCardCloseMessage(server, message) {
checkResponse(status); checkResponse(status);
return await status.json(); return await status.json();
} }

View File

@ -1,7 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardOpenMessage(server, message) { export async function setCardOpenMessage(server, message) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
@ -10,3 +10,4 @@ export async function setCardOpenMessage(server, message) {
checkResponse(status); checkResponse(status);
return await status.json(); return await status.json();
} }

View File

@ -1,10 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardProfile(token, cardId, message) { export async function setCardProfile(token, cardId, message) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'PUT', body: JSON.stringify(message) });
method: 'PUT',
body: JSON.stringify(message),
});
checkResponse(profile); checkResponse(profile);
return await profile.json(); return await profile.json()
} }

View File

@ -1,28 +1,20 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardConnecting(token, cardId) { export async function setCardConnecting(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { method: 'PUT', body: JSON.stringify('connecting') } );
method: 'PUT',
body: JSON.stringify('connecting'),
});
checkResponse(card); checkResponse(card);
return await card.json(); return await card.json();
} }
export async function setCardConnected(token, cardId, access, view, article, channel, profile) { export async function setCardConnected(token, cardId, access, view, article, channel, profile) {
let card = await fetchWithTimeout( let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}&token=${access}&viewRevision=${view}&articleRevision=${article}&channelRevision=${channel}&profileRevision=${profile}`, { method: 'PUT', body: JSON.stringify('connected') } );
`/contact/cards/${cardId}/status?agent=${token}&token=${access}&viewRevision=${view}&articleRevision=${article}&channelRevision=${channel}&profileRevision=${profile}`,
{ method: 'PUT', body: JSON.stringify('connected') },
);
checkResponse(card); checkResponse(card);
return await card.json(); return await card.json();
} }
export async function setCardConfirmed(token, cardId) { export async function setCardConfirmed(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { method: 'PUT', body: JSON.stringify('confirmed') } );
method: 'PUT',
body: JSON.stringify('confirmed'),
});
checkResponse(card); checkResponse(card);
return await card.json(); return await card.json();
} }

View File

@ -1,9 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelCard(token, channelId, cardId) { export async function setChannelCard(token, channelId, cardId ) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, { let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'PUT'});
method: 'PUT',
});
checkResponse(channel); checkResponse(channel);
return await channel.json(); return await channel.json();
} }

View File

@ -1,11 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelSubject(token, channelId, dataType, data) { export async function setChannelSubject(token, channelId, dataType, data ) {
let params = { dataType, data: JSON.stringify(data) }; let params = { dataType, data: JSON.stringify(data) };
let channel = await fetchWithTimeout(`/content/channels/${channelId}/subject?agent=${token}`, { let channel = await fetchWithTimeout(`/content/channels/${channelId}/subject?agent=${token}`, { method: 'PUT', body: JSON.stringify(params)} );
method: 'PUT',
body: JSON.stringify(params),
});
checkResponse(channel); checkResponse(channel);
return await channel.json(); return await channel.json();
} }

View File

@ -4,52 +4,45 @@ export async function setChannelTopicSubject(token, channelId, topicId, asset) {
if (asset.image) { if (asset.image) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.image); formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(['ithumb;photo', 'icopy;photo'])); let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
image: { image: {
thumb: assetEntry.find((item) => item.transform === 'ithumb;photo').assetId, thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find((item) => item.transform === 'icopy;photo').assetId, full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}, }
}; };
} else if (asset.video) { }
else if (asset.video) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.video); formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position; let thumb = 'vthumb;video;' + asset.position;
let transform = encodeURIComponent(JSON.stringify(['vlq;video', 'vhd;video', thumb])); let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", thumb]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
video: { video: {
thumb: assetEntry.find((item) => item.transform === thumb).assetId, thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find((item) => item.transform === 'vlq;video').assetId, lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find((item) => item.transform === 'vhd;video').assetId, hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}, }
}; };
} else if (asset.audio) { }
else if (asset.audio) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.audio); formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(['acopy;audio'])); let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch( let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
audio: { audio: {
label: asset.label, label: asset.label,
full: assetEntry.find((item) => item.transform === 'acopy;audio').assetId, full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}, }
}; };
} }
} }

View File

@ -1,16 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelTopicSubject(token, channelId, topicId, datatype, data) { export async function setChannelTopicSubject(token, channelId, topicId, datatype, data) {
let subject = { let subject = { data: JSON.stringify(data, (key, value) => {
data: JSON.stringify(data, (key, value) => { if (value !== null) return value
if (value !== null) return value; }), datatype };
}),
datatype,
};
let channel = await fetchWithTimeout( let channel = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}/subject?agent=${token}&confirm=true`,
`/content/channels/${channelId}/topics/${topicId}/subject?agent=${token}&confirm=true`, { method: 'PUT', body: JSON.stringify(subject) });
{ method: 'PUT', body: JSON.stringify(subject) },
);
checkResponse(channel); checkResponse(channel);
} }

View File

@ -1,7 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, asset) { export async function setContactChannelTopicSubject(server, token, channelId, topicId, asset) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
@ -9,52 +9,45 @@ export async function setContactChannelTopicSubject(server, token, channelId, to
if (asset.image) { if (asset.image) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.image); formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(['ithumb;photo', 'icopy;photo'])); let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
image: { image: {
thumb: assetEntry.find((item) => item.transform === 'ithumb;photo').assetId, thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find((item) => item.transform === 'icopy;photo').assetId, full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}, }
}; };
} else if (asset.video) { }
else if (asset.video) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.video); formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position; let thumb = "vthumb;video;" + asset.position
let transform = encodeURIComponent(JSON.stringify(['vhd;video', 'vlq;video', thumb])); let transform = encodeURIComponent(JSON.stringify(["vhd;video", "vlq;video", thumb]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
video: { video: {
thumb: assetEntry.find((item) => item.transform === thumb).assetId, thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find((item) => item.transform === 'vlq;video').assetId, lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find((item) => item.transform === 'vhd;video').assetId, hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}, }
}; };
} else if (asset.audio) { }
else if (asset.audio) {
const formData = new FormData(); const formData = new FormData();
formData.append('asset', asset.audio); formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(['acopy;audio'])); let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch( let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`,
{ method: 'POST', body: formData },
);
checkResponse(topicAsset); checkResponse(topicAsset);
let assetEntry = await topicAsset.json(); let assetEntry = await topicAsset.json();
return { return {
audio: { audio: {
label: asset.label, label: asset.label,
full: assetEntry.find((item) => item.transform === 'acopy;audio').assetId, full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}, }
}; };
} }
} }

View File

@ -1,21 +1,16 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, datatype, data) { export async function setContactChannelTopicSubject(server, token, channelId, topicId, datatype, data) {
let host = ''; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
} }
let subject = { let subject = { data: JSON.stringify(data, (key, value) => {
data: JSON.stringify(data, (key, value) => { if (value !== null) return value
if (value !== null) return value; }), datatype };
}),
datatype,
};
let channel = await fetchWithTimeout( let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`,
`${host}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`, { method: 'PUT', body: JSON.stringify(subject) });
{ method: 'PUT', body: JSON.stringify(subject) },
);
checkResponse(channel); checkResponse(channel);
} }

View File

@ -3,13 +3,9 @@ var base64 = require('base-64');
export async function setLogin(username, password, appName, appVersion, userAgent) { export async function setLogin(username, password, appName, appVersion, userAgent) {
const platform = encodeURIComponent(userAgent); const platform = encodeURIComponent(userAgent);
let headers = new Headers(); let headers = new Headers()
headers.append('Authorization', 'Basic ' + base64.encode(username + ':' + password)); headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let login = await fetchWithTimeout(`/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { let login = await fetchWithTimeout(`/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'POST', body: JSON.stringify([]), headers: headers })
method: 'POST', checkResponse(login)
body: JSON.stringify([]), return await login.json()
headers: headers,
});
checkResponse(login);
return await login.json();
} }

View File

@ -2,9 +2,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setNodeConfig(token, config) { export async function setNodeConfig(token, config) {
let body = JSON.stringify(config); let body = JSON.stringify(config);
let settings = await fetchWithTimeout(`/admin/config?setOpenAccess=true&token=${encodeURIComponent(token)}`, { let settings = await fetchWithTimeout(`/admin/config?setOpenAccess=true&token=${encodeURIComponent(token)}`, { method: 'PUT', body });
method: 'PUT',
body,
});
checkResponse(settings); checkResponse(settings);
} }

View File

@ -4,3 +4,4 @@ export async function setNodeStatus(token) {
let status = await fetchWithTimeout(`/admin/status?token=${encodeURIComponent(token)}`, { method: 'PUT' }); let status = await fetchWithTimeout(`/admin/status?token=${encodeURIComponent(token)}`, { method: 'PUT' });
checkResponse(status); checkResponse(status);
} }

View File

@ -3,6 +3,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setProfileData(token, name, location, description) { export async function setProfileData(token, name, location, description) {
let data = { name: name, location: location, description: description }; let data = { name: name, location: location, description: description };
let profile = await fetchWithTimeout(`/profile/data?agent=${token}`, { method: 'PUT', body: JSON.stringify(data) }); let profile = await fetchWithTimeout(`/profile/data?agent=${token}`, { method: 'PUT', body: JSON.stringify(data) });
checkResponse(profile); checkResponse(profile)
return await profile.json(); return await profile.json()
} }

View File

@ -2,6 +2,7 @@ import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setProfileImage(token, image) { export async function setProfileImage(token, image) {
let profile = await fetchWithTimeout(`/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) }); let profile = await fetchWithTimeout(`/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
checkResponse(profile); checkResponse(profile)
return await profile.json(); return await profile.json()
} }

View File

@ -71,8 +71,8 @@ export const CarouselWrapper = styled.div`
} }
.arrow:hover { .arrow:hover {
opacity: 1; opacity: 1;
} }
.item { .item {
margin-right: 32px; margin-right: 32px;
@ -113,3 +113,4 @@ export const CarouselWrapper = styled.div`
object-fit: contain; object-fit: contain;
} }
`; `;

View File

@ -3,64 +3,52 @@ import { CarouselWrapper } from './Carousel.styled';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
interface Props { interface Props {
pad?: any; pad?:any
items?: any; items?:any
itemRenderer?: any; itemRenderer?:any
itemRemove?: any; itemRemove?:any
} }
export function Carousel({ pad, items, itemRenderer, itemRemove }: Props) { export function Carousel({ pad, items, itemRenderer, itemRemove }:Props) {
const [slots, setSlots] = useState([]); const [slots, setSlots] = useState([]);
let carousel = useRef<any>(); let carousel = useRef<any>();
const RemoveItem = ({ index }) => { const RemoveItem = ({ index }) => {
if (itemRemove) { if (itemRemove) {
return ( return <div className="delitem" onClick={() => itemRemove(index)}><CloseOutlined /></div>
<div
className="delitem"
onClick={() => itemRemove(index)}
>
<CloseOutlined />
</div>
);
} }
return <></>; return <></>
}; }
useEffect(() => { useEffect(() => {
let assets = []; let assets = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
assets.push( assets.push((
<ReactResizeDetector <ReactResizeDetector handleWidth={true} handleHeight={false}>
handleWidth={true}
handleHeight={false}
>
{({ width, height }) => { {({ width, height }) => {
return ( return (
<div className="item noselect"> <div className="item noselect">
<div className="asset">{itemRenderer(items[i], i)}</div> <div className="asset">{ itemRenderer(items[i], i) }</div>
<RemoveItem index={i} /> <RemoveItem index={i} />
</div> </div>
); );
}} }}
</ReactResizeDetector>, </ReactResizeDetector>
); ));
} }
if (items.length > 0) { if (items.length > 0) {
assets.push(<div className="space"></div>); assets.push(<div className="space"></div>)
} }
setSlots(assets); setSlots(assets);
}, [items, itemRenderer]); }, [items, itemRenderer]);
return ( return (
<CarouselWrapper> <CarouselWrapper>
<div <div className="carousel" style={{ paddingLeft: pad + 32 }} ref={carousel}>
className="carousel"
style={{ paddingLeft: pad + 32 }}
ref={carousel}
>
{slots} {slots}
</div> </div>
</CarouselWrapper> </CarouselWrapper>
); );
} }

View File

@ -2,15 +2,20 @@ import { useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
export function useCarousel() { export function useCarousel() {
const [state, setState] = useState({});
const [state, setState] = useState({
});
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
}; }
const navigate = useNavigate(); const navigate = useNavigate();
const actions = {}; const actions = {
};
return { state, actions }; return { state, actions };
} }

View File

@ -116,3 +116,4 @@ export const DarkTheme = {
pending: '#22aaaa', pending: '#22aaaa',
confirmed: '#aaaaaa', confirmed: '#aaaaaa',
}; };

View File

@ -65,7 +65,7 @@ export const en = {
password: 'Password', password: 'Password',
newPassword: 'New Password', newPassword: 'New Password',
confirmPassword: 'Confirm Password', confirmPassword: 'Confirm Password',
deleteKey: "Type 'delete' to remove key", deleteKey: 'Type \'delete\' to remove key',
delete: 'delete', delete: 'delete',
remove: 'Delete', remove: 'Delete',
username: 'Username', username: 'Username',
@ -237,7 +237,7 @@ export const fr = {
node: 'Serveur', node: 'Serveur',
location: 'Emplacement', location: 'Emplacement',
description: 'Description', description: 'Description',
timeFormat: "Format de l'heure", timeFormat: 'Format de l\'heure',
dateFormat: 'Format de la date', dateFormat: 'Format de la date',
theme: 'Thème', theme: 'Thème',
language: 'Langue', language: 'Langue',
@ -255,10 +255,10 @@ export const fr = {
password: 'Mot de Passe', password: 'Mot de Passe',
newPassword: 'Nouveau Mot de Passe', newPassword: 'Nouveau Mot de Passe',
confirmPassword: 'Confirmer le Mot de Passe', confirmPassword: 'Confirmer le Mot de Passe',
deleteKey: "Tapez 'supprimer' pour supprimer la clé", deleteKey: 'Tapez \'supprimer\' pour supprimer la clé',
delete: 'supprimer', delete: 'supprimer',
remove: 'Supprimer', remove: 'Supprimer',
username: "Nom d'Utilisateur", username: 'Nom d\'Utilisateur',
updateProfile: 'Mettre à Jour le Profil', updateProfile: 'Mettre à Jour le Profil',
syncError: 'Erreur de Synchronisation', syncError: 'Erreur de Synchronisation',
@ -290,13 +290,13 @@ export const fr = {
create: 'Créer', create: 'Créer',
createAccount: 'Créer un Compte', createAccount: 'Créer un Compte',
accountLogin: 'Connexion au Compte', accountLogin: 'Connexion au Compte',
toCreate: "Les comptes sont créés via un lien généré depuis le tableau de bord d'administration.", toCreate: 'Les comptes sont créés via un lien généré depuis le tableau de bord d\'administration.',
admin: 'Administrateur', admin: 'Administrateur',
loginError: 'Erreur de connexion', loginError: 'Erreur de connexion',
loginMessage: "Veuillez confirmer votre nom d'utilisateur et votre mot de passe.", loginMessage: 'Veuillez confirmer votre nom d\'utilisateur et votre mot de passe.',
createError: 'Erreur de création de compte', createError: 'Erreur de création de compte',
createMessage: 'Veuillez vérifier auprès de votre administrateur.', createMessage: 'Veuillez vérifier auprès de votre administrateur.',
adminError: "Erreur d'Accès", adminError: 'Erreur d\'Accès',
adminMessage: 'Veuillez confirmer votre mot de passe', adminMessage: 'Veuillez confirmer votre mot de passe',
confirmDelete: 'Suppression de Compte', confirmDelete: 'Suppression de Compte',
@ -325,16 +325,16 @@ export const fr = {
allowUnsealed: 'Autoriser les Sujets non Sécurisés', allowUnsealed: 'Autoriser les Sujets non Sécurisés',
topicContent: 'Contenu du Sujet:', topicContent: 'Contenu du Sujet:',
enableImage: 'Activer les Images du Sujet', enableImage: 'Activer les Images du Sujet',
imageHint: "Autoriser la publication d'images dans des sujets", imageHint: 'Autoriser la publication d\'images dans des sujets',
enableAudio: "Activer l'Audio du Suject", enableAudio: 'Activer l\'Audio du Suject',
audioHint: "Autoriser la publication d'audio dans des sujets", audioHint: 'Autoriser la publication d\'audio dans des sujets',
enableVideo: 'Activer les Videos du Sujet', enableVideo: 'Activer les Videos du Sujet',
videoHint: 'Autoriser la publication de video dans des sujets', videoHint: 'Autoriser la publication de video dans des sujets',
enableWeb: 'Activer les Appels WebRTC', enableWeb: 'Activer les Appels WebRTC',
webHint: 'Autoriser les appels audio et vidéo aux contacts', webHint: 'Autoriser les appels audio et vidéo aux contacts',
serverUrl: 'URL du Serveur WebRTC', serverUrl: 'URL du Serveur WebRTC',
urlHint: 'turn:ip:port?transport=udp', urlHint: 'turn:ip:port?transport=udp',
webUsername: "Nom d'Utilisateur WebRTC", webUsername: 'Nom d\'Utilisateur WebRTC',
webPassword: 'Mot de Passe WebRTC', webPassword: 'Mot de Passe WebRTC',
failedLoad: 'Échec du Chargement', failedLoad: 'Échec du Chargement',
limit: 'Limite', limit: 'Limite',
@ -446,7 +446,7 @@ export const sp = {
password: 'Contraseña', password: 'Contraseña',
newPassword: 'Nueva Contraseña', newPassword: 'Nueva Contraseña',
confirmPassword: 'Confirmar Contraseña', confirmPassword: 'Confirmar Contraseña',
deleteKey: "Escribe 'borrar' para Eliminar la Clave", deleteKey: 'Escribe \'borrar\' para Eliminar la Clave',
delete: 'borrar', delete: 'borrar',
remove: 'Eliminar', remove: 'Eliminar',
username: 'Nombre de usuario', username: 'Nombre de usuario',
@ -567,7 +567,7 @@ export const sp = {
confirmRemove: '¿Estás seguro de que quieres eliminar el contacto?', confirmRemove: '¿Estás seguro de que quieres eliminar el contacto?',
message: 'Mensaje', message: 'Mensaje',
sealedMessage: 'Mensaje Seguro', sealedMessage: 'Mensaje Seguro',
}; }
export const pt = { export const pt = {
code: 'pt', code: 'pt',
@ -636,7 +636,7 @@ export const pt = {
password: 'Senha', password: 'Senha',
newPassword: 'Nova senha', newPassword: 'Nova senha',
confirmPassword: 'Confirmar senha', confirmPassword: 'Confirmar senha',
deleteKey: "Digite 'excluir' para deletar a chave", deleteKey: 'Digite \'excluir\' para deletar a chave',
delete: 'excluir', delete: 'excluir',
remove: 'Remover', remove: 'Remover',
username: 'Nome de usuário', username: 'Nome de usuário',
@ -757,7 +757,7 @@ export const pt = {
confirmRemove: 'Tem certeza de que deseja remover o contato?', confirmRemove: 'Tem certeza de que deseja remover o contato?',
message: 'Mensagem', message: 'Mensagem',
sealedMessage: 'Mensagem Segura', sealedMessage: 'Mensagem Segura',
}; }
export const de = { export const de = {
code: 'de', code: 'de',
@ -826,7 +826,7 @@ export const de = {
password: 'Passwort', password: 'Passwort',
newPassword: 'Neues Passwort', newPassword: 'Neues Passwort',
confirmPassword: 'Passwort bestätigen', confirmPassword: 'Passwort bestätigen',
deleteKey: "'löschen' eingeben, um den Schlüssel zu löschen", deleteKey: '\'löschen\' eingeben, um den Schlüssel zu löschen',
delete: 'löschen', delete: 'löschen',
remove: 'Entfernen', remove: 'Entfernen',
username: 'Benutzername', username: 'Benutzername',
@ -947,7 +947,7 @@ export const de = {
confirmRemove: 'Sind Sie sicher, dass Sie den Kontakt löschen möchten?', confirmRemove: 'Sind Sie sicher, dass Sie den Kontakt löschen möchten?',
message: 'Nachricht', message: 'Nachricht',
sealedMessage: 'Gesicherte Nachricht', sealedMessage: 'Gesicherte Nachricht',
}; }
export const ru = { export const ru = {
code: 'ru', code: 'ru',
@ -1016,7 +1016,7 @@ export const ru = {
password: 'Пароль', password: 'Пароль',
newPassword: 'Новый пароль', newPassword: 'Новый пароль',
confirmPassword: 'Подтвердите пароль', confirmPassword: 'Подтвердите пароль',
deleteKey: "Введите 'удалить', чтобы удалить ключ", deleteKey: 'Введите \'удалить\', чтобы удалить ключ',
delete: 'удалить', delete: 'удалить',
remove: 'Удалить', remove: 'Удалить',
username: 'Имя пользователя', username: 'Имя пользователя',
@ -1137,4 +1137,4 @@ export const ru = {
confirmRemove: 'Вы уверены, что хотите удалить контакт?', confirmRemove: 'Вы уверены, что хотите удалить контакт?',
message: 'Cообщение', message: 'Cообщение',
sealedMessage: 'Защищенное Cообщение', sealedMessage: 'Защищенное Cообщение',
}; }

View File

@ -5,5 +5,10 @@ export const AccountContext = createContext(defaultAccountContext);
export function AccountContextProvider({ children }) { export function AccountContextProvider({ children }) {
const { state, actions } = useAccountContext(); const { state, actions } = useAccountContext();
return <AccountContext.Provider value={{ state, actions }}>{children}</AccountContext.Provider>; return (
<AccountContext.Provider value={{ state, actions }}>
{children}
</AccountContext.Provider>
);
} }

View File

@ -5,5 +5,10 @@ export const AppContext = createContext(defaultAppContext);
export function AppContextProvider({ children }) { export function AppContextProvider({ children }) {
const { state, actions } = useAppContext(); const { state, actions } = useAppContext();
return <AppContext.Provider value={{ state, actions }}>{children}</AppContext.Provider>; return (
<AppContext.Provider value={{ state, actions }}>
{children}
</AppContext.Provider>
);
} }

View File

@ -5,5 +5,10 @@ export const CardContext = createContext(defaultCardContext);
export function CardContextProvider({ children }) { export function CardContextProvider({ children }) {
const { state, actions } = useCardContext(); const { state, actions } = useCardContext();
return <CardContext.Provider value={{ state, actions }}>{children}</CardContext.Provider>; return (
<CardContext.Provider value={{ state, actions }}>
{children}
</CardContext.Provider>
);
} }

View File

@ -5,5 +5,10 @@ export const ChannelContext = createContext(defaultChannelContext);
export function ChannelContextProvider({ children }) { export function ChannelContextProvider({ children }) {
const { state, actions } = useChannelContext(); const { state, actions } = useChannelContext();
return <ChannelContext.Provider value={{ state, actions }}>{children}</ChannelContext.Provider>; return (
<ChannelContext.Provider value={{ state, actions }}>
{children}
</ChannelContext.Provider>
);
} }

View File

@ -5,5 +5,10 @@ export const ConversationContext = createContext(defaultConversionContext);
export function ConversationContextProvider({ children }) { export function ConversationContextProvider({ children }) {
const { state, actions } = useConversationContext(); const { state, actions } = useConversationContext();
return <ConversationContext.Provider value={{ state, actions }}>{children}</ConversationContext.Provider>; return (
<ConversationContext.Provider value={{ state, actions }}>
{children}
</ConversationContext.Provider>
);
} }

View File

@ -5,5 +5,10 @@ export const ProfileContext = createContext(defaultProfileContext);
export function ProfileContextProvider({ children }) { export function ProfileContextProvider({ children }) {
const { state, actions } = useProfileContext(); const { state, actions } = useProfileContext();
return <ProfileContext.Provider value={{ state, actions }}>{children}</ProfileContext.Provider>; return (
<ProfileContext.Provider value={{ state, actions }}>
{children}
</ProfileContext.Provider>
);
} }

Some files were not shown because too many files have changed in this diff Show More