mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
support admin disable of accounts
This commit is contained in:
parent
172d28f0be
commit
8ff747f90f
35
doc/api.oa3
35
doc/api.oa3
@ -212,10 +212,8 @@ paths:
|
||||
delete:
|
||||
tags:
|
||||
- admin
|
||||
description: Remove account from node. Access granted to admin username and password.
|
||||
description: Remove account from node. Access granted to admin token
|
||||
operationId: remove-node-account
|
||||
security:
|
||||
- basicAuth: []
|
||||
parameters:
|
||||
- name: accountId
|
||||
in: path
|
||||
@ -238,6 +236,37 @@ paths:
|
||||
description: account not found
|
||||
'500':
|
||||
description: internal server error
|
||||
put:
|
||||
tags:
|
||||
- admin
|
||||
description: Disable account. Access granted to admin token
|
||||
operationId: set-node-account
|
||||
parameters:
|
||||
- name: accountId
|
||||
in: path
|
||||
description: id of account to delete
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: token
|
||||
in: query
|
||||
description: token for admin access
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: boolean
|
||||
'401':
|
||||
description: invalid authentication
|
||||
'404':
|
||||
description: account not found
|
||||
'500':
|
||||
description: internal server error
|
||||
|
||||
/admin/accounts/import:
|
||||
post:
|
||||
|
38
net/server/internal/api_setNodeAccountStatus.go
Normal file
38
net/server/internal/api_setNodeAccountStatus.go
Normal file
@ -0,0 +1,38 @@
|
||||
package databag
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"net/http"
|
||||
"github.com/gorilla/mux"
|
||||
"databag/internal/store"
|
||||
)
|
||||
|
||||
func SetNodeAccountStatus(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// get referenced account id
|
||||
params := mux.Vars(r)
|
||||
accountId, res := strconv.ParseUint(params["accountId"], 10, 32)
|
||||
if res != nil {
|
||||
ErrResponse(w, http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
|
||||
if code, err := ParamAdminToken(r); err != nil {
|
||||
ErrResponse(w, code, err)
|
||||
return
|
||||
}
|
||||
|
||||
var flag bool
|
||||
if err := ParseRequest(r, w, &flag); err != nil {
|
||||
ErrResponse(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := store.DB.Model(store.Account{}).Where("id = ?", accountId).Update("disabled", flag).Error; err != nil {
|
||||
ErrResponse(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
WriteResponse(w, nil)
|
||||
}
|
||||
|
@ -193,6 +193,13 @@ var routes = Routes{
|
||||
GetNodeAccountImage,
|
||||
},
|
||||
|
||||
Route{
|
||||
"SetNodeAccountStatus",
|
||||
strings.ToUpper("Put"),
|
||||
"/admin/accounts/{accountId}/status",
|
||||
SetNodeAccountStatus,
|
||||
},
|
||||
|
||||
Route{
|
||||
"GetNodeAccounts",
|
||||
strings.ToUpper("Get"),
|
||||
|
@ -2,6 +2,7 @@ import { Avatar } from 'avatar/Avatar';
|
||||
import { AccountItemWrapper, DeleteButton, EnableButton, DisableButton, ResetButton } from './AccountItem.styled';
|
||||
import { useAccountItem } from './useAccountItem.hook';
|
||||
import { UserDeleteOutlined, UnlockOutlined, CloseCircleOutlined, CheckCircleOutlined } from '@ant-design/icons';
|
||||
import { Tooltip } from 'antd';
|
||||
|
||||
export function AccountItem({ token, item }) {
|
||||
|
||||
@ -9,9 +10,19 @@ export function AccountItem({ token, item }) {
|
||||
|
||||
const Enable = () => {
|
||||
if (state.disabled) {
|
||||
return <EnableButton type="text" size="large" icon={<CloseCircleOutlined />}></EnableButton>
|
||||
return (
|
||||
<Tooltip placement="topLeft" title="Enable Account">
|
||||
<EnableButton type="text" size="large" icon={<CheckCircleOutlined />}
|
||||
onClick={() => actions.setStatus(false)}></EnableButton>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
return <DisableButton type="text" size="large" icon={<CheckCircleOutlined />}></DisableButton>
|
||||
return (
|
||||
<Tooltip placement="topLeft" title="Disable Account">
|
||||
<DisableButton type="text" size="large" icon={<CloseCircleOutlined />}
|
||||
onClick={() => actions.setStatus(true)}></DisableButton>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -19,14 +30,18 @@ export function AccountItem({ token, item }) {
|
||||
<div class="avatar">
|
||||
<Avatar imageUrl={state.imageUrl} />
|
||||
</div>
|
||||
<div class="id">
|
||||
<div class={state.activeClass}>
|
||||
<div class="handle">{ state.handle }</div>
|
||||
<div class="guid">{ state.guid }</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<ResetButton type="text" size="large" icon={<UnlockOutlined />}></ResetButton>
|
||||
<Tooltip placement="topLeft" title="Reset Password">
|
||||
<ResetButton type="text" size="large" icon={<UnlockOutlined />}></ResetButton>
|
||||
</Tooltip>
|
||||
<Enable />
|
||||
<DeleteButton type="text" size="large" icon={<UserDeleteOutlined />}></DeleteButton>
|
||||
<Tooltip placement="topLeft" title="Delete Account">
|
||||
<DeleteButton type="text" size="large" icon={<UserDeleteOutlined />}></DeleteButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</AccountItemWrapper>
|
||||
);
|
||||
|
@ -11,6 +11,7 @@ export const AccountItemWrapper = styled.div`
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #eeeeee;
|
||||
@ -23,29 +24,38 @@ export const AccountItemWrapper = styled.div`
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.id {
|
||||
.inactive {
|
||||
padding-left: 16px;
|
||||
padding-right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.handle {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.active {
|
||||
padding-left: 16px;
|
||||
padding-right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.guid {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.handle {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.control {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
.guid {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.control {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { useContext, useState, useEffect } from 'react';
|
||||
import { getAccountImageUrl } from 'api/getAccountImageUrl';
|
||||
import { setAccountStatus } from 'api/setAccountStatus';
|
||||
|
||||
export function useAccountItem(token, item) {
|
||||
|
||||
const [state, setState] = useState({
|
||||
statusBusy: false,
|
||||
});
|
||||
|
||||
const updateState = (value) => {
|
||||
@ -12,16 +14,31 @@ export function useAccountItem(token, item) {
|
||||
|
||||
useEffect(() => {
|
||||
updateState({
|
||||
disabled: false,
|
||||
disabled: item?.disabled,
|
||||
activeClass: item?.disabled ? 'inactive' : 'active',
|
||||
accountId: item?.accountId,
|
||||
name: item?.name,
|
||||
guid: item?.guid,
|
||||
handle: item?.handle,
|
||||
imageUrl: item?.imageSet ? getAccountImageUrl(token, item?.accountId) : null,
|
||||
});
|
||||
}, []);
|
||||
}, [token, item]);
|
||||
|
||||
const actions = {
|
||||
setStatus: async (disabled) => {
|
||||
if (!state.statusBusy) {
|
||||
updateState({ statusBusy: true });
|
||||
try {
|
||||
await setAccountStatus(token, item.accountId, disabled);
|
||||
updateState({ disabled, activeClass: disabled ? 'inactive' : 'active' });
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
window.alert(err);
|
||||
}
|
||||
updateState({ statusBusy: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DashboardWrapper, SettingsButton, AddButton, SettingsLayout } from './Dashboard.styled';
|
||||
import { Button, Modal, Input, InputNumber, Space, List } from 'antd';
|
||||
import { Tooltip, Button, Modal, Input, InputNumber, Space, List } from 'antd';
|
||||
import { SettingOutlined, UserAddOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import { useDashboard } from './useDashboard.hook';
|
||||
import { AccountItem } from './AccountItem/AccountItem';
|
||||
@ -15,19 +15,27 @@ export function Dashboard({ token, config, logout }) {
|
||||
<div class="header">
|
||||
<div class="label">Accounts</div>
|
||||
<div class="settings">
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.getAccounts()}></SettingsButton>
|
||||
<Tooltip placement="topRight" title="Reload Accounts">
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.getAccounts()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="settings">
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
<Tooltip placement="topRight" title="Configure Server">
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="settings">
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => logout()}></SettingsButton>
|
||||
<Tooltip placement="topRight" title="Logout">
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => logout()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="add">
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}></AddButton>
|
||||
<Tooltip placement="topRight" title="Add Account">
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}></AddButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
7
net/web/src/api/setAccountStatus.js
Normal file
7
net/web/src/api/setAccountStatus.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setAccountStatus(token, accountId, disabled) {
|
||||
let res = await fetchWithTimeout(`/admin/accounts/${accountId}/status?token=${token}`, { method: 'PUT', body: JSON.stringify(disabled) })
|
||||
checkResponse(res);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user