diff --git a/net/server/internal/api_addAccount.go b/net/server/internal/api_addAccount.go
index d86aefd9..21e20bcc 100644
--- a/net/server/internal/api_addAccount.go
+++ b/net/server/internal/api_addAccount.go
@@ -12,8 +12,15 @@ import (
func AddAccount(w http.ResponseWriter, r *http.Request) {
var token *store.AccountToken
+ var res error
- if r.Header.Get("Authorization") == "" {
+ if r.FormValue("token") != "" {
+ token, _, res = AccessToken(r)
+ if res != nil || token.TokenType != APP_TOKENCREATE {
+ ErrResponse(w, http.StatusUnauthorized, res)
+ return
+ }
+ } else {
if available, err := getAvailableAccounts(); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
@@ -21,13 +28,6 @@ func AddAccount(w http.ResponseWriter, r *http.Request) {
ErrResponse(w, http.StatusForbidden, errors.New("no open accounts available"))
return
}
- } else {
- var err error
- token, err = BearerAccountToken(r);
- if err != nil || token.TokenType != APP_TOKENCREATE {
- ErrResponse(w, http.StatusUnauthorized, err)
- return
- }
}
username, password, ret := BasicCredentials(r);
diff --git a/net/server/internal/api_getAccountUsername.go b/net/server/internal/api_getAccountUsername.go
index c0855630..ed1d968c 100644
--- a/net/server/internal/api_getAccountUsername.go
+++ b/net/server/internal/api_getAccountUsername.go
@@ -11,21 +11,19 @@ type accountUsername struct {
}
func GetAccountUsername(w http.ResponseWriter, r *http.Request) {
- var token *store.AccountToken
- if r.Header.Get("Authorization") == "" {
+ if r.FormValue("token") != "" {
+ token, _, res := AccessToken(r)
+ if res != nil || token.TokenType != APP_TOKENCREATE {
+ ErrResponse(w, http.StatusUnauthorized, res)
+ return
+ }
+ } else {
if available, err := getAvailableAccounts(); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
} else if available == 0 {
- ErrResponse(w, http.StatusUnauthorized, errors.New("no open accounts available"))
- return
- }
- } else {
- var err error
- token, err = BearerAccountToken(r);
- if err != nil || token.TokenType != APP_TOKENCREATE {
- ErrResponse(w, http.StatusUnauthorized, err)
+ ErrResponse(w, http.StatusForbidden, errors.New("no open accounts available"))
return
}
}
diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go
index cd8261dd..daa9e899 100644
--- a/net/server/internal/routers.go
+++ b/net/server/internal/routers.go
@@ -34,7 +34,7 @@ func NewRouter() *mux.Router {
Handler(handler)
}
- fs := http.FileServer(http.Dir("/data/databag/net/web/build/"))
+ fs := http.FileServer(http.Dir("/app/databag/net/web/build/"))
router.PathPrefix("/").Handler(http.StripPrefix("/", fs))
return router
diff --git a/net/web/src/Admin/Dashboard/AccountItem/AccountItem.jsx b/net/web/src/Admin/Dashboard/AccountItem/AccountItem.jsx
index 38ef868a..7f15079c 100644
--- a/net/web/src/Admin/Dashboard/AccountItem/AccountItem.jsx
+++ b/net/web/src/Admin/Dashboard/AccountItem/AccountItem.jsx
@@ -45,7 +45,7 @@ export function AccountItem({ token, item, remove }) {
}
- onClick={() => actions.setAccessLink()}>
+ loading={state.accessBusy} onClick={() => actions.setAccessLink()}>
@@ -53,7 +53,7 @@ export function AccountItem({ token, item, remove }) {
loading={state.removeBusy} onClick={() => actions.remove()}>
- actions.setShowAccess(false)}>OK ]}
onCancel={() => actions.setShowAccess(false)}>
diff --git a/net/web/src/Admin/Dashboard/AccountItem/useAccountItem.hook.js b/net/web/src/Admin/Dashboard/AccountItem/useAccountItem.hook.js
index 81700fa2..59c44759 100644
--- a/net/web/src/Admin/Dashboard/AccountItem/useAccountItem.hook.js
+++ b/net/web/src/Admin/Dashboard/AccountItem/useAccountItem.hook.js
@@ -8,6 +8,7 @@ export function useAccountItem(token, item, remove) {
const [state, setState] = useState({
statusBusy: false,
removeBusy: false,
+ accessBusy: false,
showAccess: false,
});
@@ -29,8 +30,17 @@ export function useAccountItem(token, item, remove) {
const actions = {
setAccessLink: async () => {
- let access = await addAccountAccess(token, item.accountId);
- updateState({ accessToken: access, showAccess: true });
+ if (!state.accessBusy) {
+ updateState({ accessBusy: true });
+ try {
+ let access = await addAccountAccess(token, item.accountId);
+ updateState({ accessToken: access, showAccess: true });
+ }
+ catch (err) {
+ window.alert(err);
+ }
+ updateState({ accessBusy: false });
+ }
},
setShowAccess: (showAccess) => {
updateState({ showAccess });
diff --git a/net/web/src/Admin/Dashboard/Dashboard.jsx b/net/web/src/Admin/Dashboard/Dashboard.jsx
index a200d73f..1a9fa496 100644
--- a/net/web/src/Admin/Dashboard/Dashboard.jsx
+++ b/net/web/src/Admin/Dashboard/Dashboard.jsx
@@ -1,6 +1,6 @@
-import { DashboardWrapper, SettingsButton, AddButton, SettingsLayout } from './Dashboard.styled';
+import { DashboardWrapper, SettingsButton, AddButton, SettingsLayout, CreateLayout } from './Dashboard.styled';
import { Tooltip, Button, Modal, Input, InputNumber, Space, List } from 'antd';
-import { SettingOutlined, UserAddOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons';
+import { SettingOutlined, CopyOutlined, UserAddOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons';
import { useDashboard } from './useDashboard.hook';
import { AccountItem } from './AccountItem/AccountItem';
@@ -8,6 +8,14 @@ export function Dashboard({ token, config, logout }) {
const { state, actions } = useDashboard(token, config);
+ const onClipboard = (value) => {
+ navigator.clipboard.writeText(value);
+ };
+
+ const createLink = () => {
+ return window.location.origin + '/#/create?add=' + state.createToken;
+ };
+
return (
@@ -34,7 +42,8 @@ export function Dashboard({ token, config, logout }) {
- }>
+ }
+ loading={state.createBusy} onClick={() => actions.setCreateLink()}>
@@ -60,13 +69,22 @@ export function Dashboard({ token, config, logout }) {
value={state.host} />
-
Account Storage (GB):
+
Storage Limit (GB) / Account:
actions.setStorage(e)}
placeholder="0 for unrestricted" value={state.storage} />
-
+ actions.setShowCreate(false)}>OK ]}
+ onCancel={() => actions.setShowCreate(false)}>
+
+ {createLink()}
+ } size="small"
+ onClick={() => onClipboard(createLink())}
+ />
+
+
);
}
diff --git a/net/web/src/Admin/Dashboard/Dashboard.styled.js b/net/web/src/Admin/Dashboard/Dashboard.styled.js
index fa7339be..9d14f55e 100644
--- a/net/web/src/Admin/Dashboard/Dashboard.styled.js
+++ b/net/web/src/Admin/Dashboard/Dashboard.styled.js
@@ -84,3 +84,7 @@ export const SettingsLayout = styled(Space)`
align-items: center;
}
`;
+
+export const CreateLayout = styled(Space)`
+ white-space: nowrap;
+`
diff --git a/net/web/src/Admin/Dashboard/useDashboard.hook.js b/net/web/src/Admin/Dashboard/useDashboard.hook.js
index 219d3e81..65e46156 100644
--- a/net/web/src/Admin/Dashboard/useDashboard.hook.js
+++ b/net/web/src/Admin/Dashboard/useDashboard.hook.js
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { setNodeConfig } from 'api/setNodeConfig';
import { getNodeAccounts } from 'api/getNodeAccounts';
import { removeAccount } from 'api/removeAccount';
+import { addAccountCreate } from 'api/addAccountCreate';
export function useDashboard(token, config) {
@@ -12,6 +13,8 @@ export function useDashboard(token, config) {
busy: false,
loading: false,
accounts: [],
+ createBusy: false,
+ showCreate: false,
});
const updateState = (value) => {
@@ -19,6 +22,22 @@ export function useDashboard(token, config) {
}
const actions = {
+ setCreateLink: async () => {
+ if (!state.createBusy) {
+ updateState({ createBusy: true });
+ try {
+ let create = await addAccountCreate(token)
+ updateState({ createToken: create, showCreate: true });
+ }
+ catch (err) {
+ window.alert(err);
+ }
+ updateState({ createBusy: false });
+ }
+ },
+ setShowCreate: (showCreate) => {
+ updateState({ showCreate });
+ },
removeAccount: async (accountId) => {
await removeAccount(token, accountId);
actions.getAccounts();
diff --git a/net/web/src/Create/useCreate.hook.js b/net/web/src/Create/useCreate.hook.js
index 094d0781..2a8a1b89 100644
--- a/net/web/src/Create/useCreate.hook.js
+++ b/net/web/src/Create/useCreate.hook.js
@@ -1,6 +1,6 @@
import { useContext, useState, useEffect, useRef } from 'react';
import { AppContext } from 'context/AppContext';
-import { useNavigate } from "react-router-dom";
+import { useNavigate, useLocation } from "react-router-dom";
export function useCreate() {
const [checked, setChecked] = useState(true)
@@ -10,10 +10,12 @@ export function useCreate() {
confirmed: '',
conflict: '',
spinning: false,
+ token: null,
});
const navigate = useNavigate();
const app = useContext(AppContext);
+ const { search } = useLocation();
const debounce = useRef(null)
const actions = {
@@ -41,7 +43,7 @@ export function useCreate() {
if (!state.spinning) {
actions.updateState({ spinning: true })
try {
- await app.actions.create(state.username, state.password)
+ await app.actions.create(state.username, state.password, state.token)
}
catch (err) {
window.alert(err);
@@ -64,7 +66,7 @@ export function useCreate() {
actions.updateState({ conflict: '' })
}
else {
- let valid = await app.actions.username(name)
+ let valid = await app.actions.username(name, state.token)
setChecked(true)
if (!valid) {
actions.updateState({ conflict: 'not available' })
@@ -82,8 +84,12 @@ export function useCreate() {
if (app.state.access === 'user') {
navigate('/user')
}
- if (app.state.access === 'admin') {
- navigate('/admin')
+ else {
+ let params = new URLSearchParams(search);
+ let token = params.get("add");
+ if (token) {
+ actions.updateState({ token });
+ }
}
}
}
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx
index 10c88886..958cae67 100644
--- a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx
@@ -43,10 +43,16 @@ export function ChannelLabel({ item }) {
}
if (item?.data?.channelDetail?.data) {
- let data = JSON.parse(item.data.channelDetail.data);
- if (data.subject != '' && data.subject != null) {
- setSubject(data.subject);
- return
+ try {
+ let data = JSON.parse(item.data.channelDetail.data);
+ if (data.subject != '' && data.subject != null) {
+ setSubject(data.subject);
+ return
+ }
+ }
+ catch (err) {
+ console.log(err);
+ setSubject(null);
}
}
setSubject(contacts.join(', '));
diff --git a/net/web/src/api/addAccount.js b/net/web/src/api/addAccount.js
new file mode 100644
index 00000000..6eccf8e3
--- /dev/null
+++ b/net/web/src/api/addAccount.js
@@ -0,0 +1,15 @@
+import { checkResponse, fetchWithTimeout } from './fetchUtil';
+var base64 = require('base-64');
+
+export async function addAccount(username, password, token) {
+ let access = "";
+ if (token) {
+ access = `?token=${token}`
+ }
+ let headers = new Headers()
+ headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
+ let profile = await fetchWithTimeout(`/account/profile${access}`, { method: 'POST', headers: headers })
+ checkResponse(profile);
+ return await profile.json()
+}
+
diff --git a/net/web/src/api/addAccountCreate.js b/net/web/src/api/addAccountCreate.js
new file mode 100644
index 00000000..49e4015e
--- /dev/null
+++ b/net/web/src/api/addAccountCreate.js
@@ -0,0 +1,8 @@
+import { checkResponse, fetchWithTimeout } from './fetchUtil';
+
+export async function addAccountCreate(token) {
+ let access = await fetchWithTimeout(`/admin/accounts?token=${token}`, { method: 'POST' })
+ checkResponse(access);
+ return await access.json()
+}
+
diff --git a/net/web/src/api/getUsername.js b/net/web/src/api/getUsername.js
index e7f3b8db..65854f7c 100644
--- a/net/web/src/api/getUsername.js
+++ b/net/web/src/api/getUsername.js
@@ -1,7 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
-export async function getUsername(name) {
- let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name), { method: 'GET' })
+export async function getUsername(name, token) {
+ let access = "";
+ if (token) {
+ access = `&token=${token}`
+ }
+ let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name) + access, { method: 'GET' })
checkResponse(available)
return await available.json()
}
diff --git a/net/web/src/context/fetchUtil.js b/net/web/src/context/fetchUtil.js
index 136c820f..1e943267 100644
--- a/net/web/src/context/fetchUtil.js
+++ b/net/web/src/context/fetchUtil.js
@@ -21,12 +21,6 @@ export async function getAvailable() {
return await available.json()
}
-export async function getUsername(name) {
- let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name), { method: 'GET', timeout: FETCH_TIMEOUT })
- checkResponse(available)
- return await available.json()
-}
-
export async function setLogin(username, password) {
let headers = new Headers()
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
diff --git a/net/web/src/context/useAppContext.hook.js b/net/web/src/context/useAppContext.hook.js
index 18644ecf..8ffcc347 100644
--- a/net/web/src/context/useAppContext.hook.js
+++ b/net/web/src/context/useAppContext.hook.js
@@ -1,7 +1,9 @@
import { useEffect, useState, useRef, useContext } from 'react';
import { useNavigate, useLocation, useParams } from "react-router-dom";
-import { getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
+import { getAvailable, setLogin } from './fetchUtil';
import { setAccountAccess } from 'api/setAccountAccess';
+import { addAccount } from 'api/addAccount';
+import { getUsername } from 'api/getUsername';
import { AccountContext } from './AccountContext';
import { ProfileContext } from './ProfileContext';
import { ArticleContext } from './ArticleContext';
@@ -9,8 +11,8 @@ import { GroupContext } from './GroupContext';
import { CardContext } from './CardContext';
import { ChannelContext } from './ChannelContext';
-async function appCreate(username, password, updateState, setWebsocket) {
- await createAccount(username, password);
+async function appCreate(username, password, token, updateState, setWebsocket) {
+ await addAccount(username, password, token);
let access = await setLogin(username, password)
updateState({ token: access, access: 'user' });
setWebsocket(access)
@@ -95,8 +97,8 @@ export function useAppContext() {
login: async (username, password) => {
await appLogin(username, password, updateState, setWebsocket)
},
- create: async (username, password) => {
- await appCreate(username, password, updateState, setWebsocket)
+ create: async (username, password, token) => {
+ await appCreate(username, password, token, updateState, setWebsocket)
},
username: getUsername,
available: getAvailable,