syncing group list

This commit is contained in:
Roland Osborne 2022-03-17 00:14:34 -07:00
parent 955efe1d67
commit 037e5ebb71
5 changed files with 108 additions and 42 deletions

View File

@ -38,7 +38,7 @@ func GetGroups(w http.ResponseWriter, r *http.Request) {
}
}
var response []*Group
response := []*Group{}
for _, slot := range slots {
response = append(response, getGroupModel(&slot))
}

View File

@ -1,5 +1,5 @@
import { createContext } from 'react';
import useAppContext from './useAppContext.hook';
import { useAppContext } from './useAppContext.hook';
export const AppContext = createContext({});

View File

@ -43,3 +43,13 @@ export async function createAccount(username, password) {
checkResponse(profile);
return await profile.json()
}
export async function getGroups(token, revision) {
let headers = new Headers()
headers.append('Authorization', 'Bearer ' + token);
let param = revision == null ? '' : '?revision=' + revision
let groups = await fetchWithTimeout('/alias/groups' + param, { method: 'GET', timeout: FETCH_TIMEOUT, headers: headers });
checkResponse(groups)
return await groups.json()
}

View File

@ -1,53 +1,103 @@
import { useEffect, useState, useRef } from 'react';
import { getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
import { getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil';
export default function useAppContext() {
const [state, setAppState] = useState(null);
async function updateGroups(token, revision, groupMap) {
let groups = await getGroups(token, revision);
for (let group of groups) {
groupMap.set(group.id, group);
}
}
async function appCreate(username, password, updateState, setWebsocket) {
await createAccount(username, password);
let access = await setLogin(username, password)
updateState({ token: access, access: 'user' });
setWebsocket(access)
localStorage.setItem("session", JSON.stringify({ token: access, access: 'user' }));
}
async function appLogin(username, password, updateState, setWebsocket) {
let access = await setLogin(username, password)
updateState({ token: access, access: 'user' });
setWebsocket(access)
localStorage.setItem("session", JSON.stringify({ token: access, access: 'user' }));
}
function appLogout(updateState, clearWebsocket) {
updateState({ token: null, access: null });
clearWebsocket()
localStorage.removeItem("session");
}
export function useAppContext() {
const [state, setState] = useState(null);
const groupRevision = useRef(null);
const groups = useRef(new Map());
const ws = useRef(null);
const login = async (username, password) => {
let access = await setLogin(username, password)
setAppState({ appToken: access, access: 'user' });
localStorage.setItem("session", JSON.stringify({ token: access, access: 'user' }));
connectStatus(access);
const revision = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const create = async (username, password) => {
await createAccount(username, password);
try {
await login(username, password)
} catch(err) {
throw new Error("login failed after account createion")
}
}
const logout = () => {
ws.current.onclose = () => {}
ws.current.close()
ws.current = null
setAppState({ actions: accessActions })
localStorage.removeItem("session");
const updateData = (value) => {
setState((s) => {
let data = { ...s.Data, ...value }
return { ...s, Data: data }
})
}
const userActions = {
logout: logout,
logout: () => {
appLogout(updateState, clearWebsocket);
}
}
const adminActions = {
logout: logout,
logout: () => {
appLogout(updateState, clearWebsocket);
}
}
const accessActions = {
login: login,
create: create,
login: async (username, password) => {
await appLogin(username, password, updateState, setWebsocket)
},
create: async (username, password) => {
await appCreate(username, password, updateState, setWebsocket)
},
username: getUsername,
available: getAvailable,
}
const connectStatus = (token) => {
const processRevision = async (token) => {
while(revision.current != null) {
let rev = revision.current;
// update group if revision changed
if (rev.group != groupRevision.current) {
await updateGroups(token, groupRevision.current, groups.current);
updateData({ groups: Array.from(groups.current.values()) });
groupRevision.current = rev.group
}
// check if new revision was received during processing
if (rev == revision.current) {
revision.current = null
}
}
}
const setWebsocket = (token) => {
ws.current = new WebSocket("wss://" + window.location.host + "/status");
ws.current.onmessage = (ev) => {
console.log(ev)
if (revision.current != null) {
revision.current = JSON.parse(ev.data);
}
else {
revision.current = JSON.parse(ev.data);
processRevision(token)
}
}
ws.current.onclose = () => {
console.log('ws close')
@ -57,7 +107,7 @@ export default function useAppContext() {
ws.current.onclose = () => {}
ws.current.onopen = () => {}
ws.current.onerror = () => {}
connectStatus(token)
setWebsocket(token);
}
}, 2000)
}
@ -69,27 +119,33 @@ export default function useAppContext() {
}
}
const clearWebsocket = () => {
ws.current.onclose = () => {}
ws.current.close()
ws.current = null
}
useEffect(() => {
const storage = localStorage.getItem('session');
if (storage != null) {
try {
const session = JSON.parse(storage)
if (session?.access === 'admin') {
setAppState({ token: session.token, access: session.access })
connectStatus(session.token);
setState({ token: session.token, access: session.access })
setWebsocket(session.token);
} else if (session?.access === 'user') {
setAppState({ token: session.token, access: session.access })
connectStatus(session.token);
setState({ token: session.token, access: session.access })
setWebsocket(session.token);
} else {
setAppState({})
setState({})
}
}
catch(err) {
console.log(err)
setAppState({})
setState({})
}
} else {
setAppState({})
setState({})
}
}, []);

View File

@ -18,7 +18,7 @@ export function Create() {
addonAfter={state.conflict} />
<CreatePassword size="large" spellCheck="false" placeholder="password" prefix={<LockOutlined />}
onChange={(e) => actions.setPassword(e.target.value)} value={state.password} />
<CreatePassword size="large" spellCheck="false" placeholder="password" prefix={<LockOutlined />}
<CreatePassword size="large" spellCheck="false" placeholder="confirm password" prefix={<LockOutlined />}
onChange={(e) => actions.setConfirmed(e.target.value)} value={state.confirmed} />
<CreateEnter type="primary" onClick={() => actions.onCreate()} disabled={actions.isDisabled()}>
<span>Create Account</span>