Still refactoring...
This commit is contained in:
parent
a0bed34b43
commit
f4ba7afb69
|
@ -1,13 +1,13 @@
|
||||||
import { createForm } from '@felte/solid';
|
import { createForm } from '@felte/solid';
|
||||||
import reporter from '@felte/reporter-tippy';
|
import reporter from '@felte/reporter-tippy';
|
||||||
import { Button, Dialog, TextField } from '@kobalte/core';
|
import { Button, Dialog, TextField } from '@kobalte/core';
|
||||||
import { Component, createSignal } from 'solid-js';
|
import { Component, createSignal, JSXElement, Show } from 'solid-js';
|
||||||
import 'tippy.js/dist/tippy.css';
|
import 'tippy.js/dist/tippy.css';
|
||||||
|
|
||||||
interface CredentialsType {
|
interface CredentialsType {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
hostname?: string;
|
database: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [adminCredentials, setAdminCredentials] = createSignal<CredentialsType>();
|
const [adminCredentials, setAdminCredentials] = createSignal<CredentialsType>();
|
||||||
|
@ -155,3 +155,13 @@ const Credentials: Component<Props> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Credentials;
|
export default Credentials;
|
||||||
|
|
||||||
|
export const CheckCredentials: Component<{ children: JSXElement }> = (
|
||||||
|
props
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<Show when={!!adminCredentials()} fallback={<Credentials />}>
|
||||||
|
{props.children}
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export { default, adminCredentials } from './Credentials';
|
export { default, adminCredentials, CheckCredentials } from './Credentials';
|
||||||
|
|
|
@ -1,88 +1,30 @@
|
||||||
import { createForm } from '@felte/solid';
|
import { createForm } from '@felte/solid';
|
||||||
import { Component, createSignal, Match, Switch } from 'solid-js';
|
import { Component, createEffect, Match, Switch } from 'solid-js';
|
||||||
import { TextField, Button, Dialog } from '@kobalte/core';
|
import { TextField, Button } from '@kobalte/core';
|
||||||
|
import reporter from '@felte/reporter-tippy';
|
||||||
import './style.css';
|
|
||||||
import { createServerAction$ } from 'solid-start/server';
|
|
||||||
import PouchDb from 'pouchdb';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { put } from '~/lib/db';
|
import './style.css';
|
||||||
import { useNavigate } from 'solid-start';
|
import { useNavigate } from 'solid-start';
|
||||||
import { toHex } from '~/lib/to-hex';
|
import { adminCredentials } from '../credentials';
|
||||||
import { cloneDeep } from 'lodash';
|
import { put } from '~/lib/put';
|
||||||
|
import { del } from '~/lib/del';
|
||||||
|
import { isFunction } from 'lodash';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
values?: any;
|
values?: () => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const User: Component<Props> = (props) => {
|
const User: Component<Props> = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [openDialog, setOpenDialog] = createSignal(false);
|
const getValues = () => {
|
||||||
const [openUsernamePasswordDialog, setOpenUserNamePasswordDialog] =
|
if (!isFunction(props?.values)) {
|
||||||
createSignal(false);
|
return null;
|
||||||
|
}
|
||||||
|
return props.values();
|
||||||
|
};
|
||||||
|
|
||||||
const [status, setStatus] = createSignal<string>();
|
const isNew = () => !getValues();
|
||||||
|
|
||||||
const [saving, save] = createServerAction$(async (args: any) => {
|
|
||||||
const { props, values } = args;
|
|
||||||
console.log({
|
|
||||||
caller: 'User / save',
|
|
||||||
props,
|
|
||||||
values,
|
|
||||||
args,
|
|
||||||
id: props.values?._id,
|
|
||||||
});
|
|
||||||
const db = new PouchDb('.db');
|
|
||||||
const id = props.values?._id ?? `user/${uuid()}`;
|
|
||||||
await put({
|
|
||||||
db,
|
|
||||||
doc: {
|
|
||||||
_id: id,
|
|
||||||
date: new Date().toISOString(),
|
|
||||||
type: 'user',
|
|
||||||
...values,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return id;
|
|
||||||
});
|
|
||||||
|
|
||||||
const [dbChecking, dbCheck] = createServerAction$(async (args: any) => {
|
|
||||||
console.log({
|
|
||||||
caller: 'User / dbCheck',
|
|
||||||
args,
|
|
||||||
});
|
|
||||||
let baseDbInfoAuth;
|
|
||||||
try {
|
|
||||||
const baseDb = new PouchDb(cloneDeep(args));
|
|
||||||
baseDbInfoAuth = await baseDb.info();
|
|
||||||
} catch (error) {
|
|
||||||
baseDbInfoAuth = { error };
|
|
||||||
}
|
|
||||||
let baseDbInfoAnon;
|
|
||||||
try {
|
|
||||||
const baseDb = new PouchDb(args.name);
|
|
||||||
baseDbInfoAnon = await baseDb.info();
|
|
||||||
} catch (error) {
|
|
||||||
baseDbInfoAnon = { error };
|
|
||||||
}
|
|
||||||
const name = `${args.name}/userdb-${toHex(args.auth.username)}`;
|
|
||||||
let userDbInfo;
|
|
||||||
try {
|
|
||||||
const userDb = new PouchDb({ ...args, name });
|
|
||||||
userDbInfo = await userDb.info();
|
|
||||||
} catch (error) {
|
|
||||||
userDbInfo = { error };
|
|
||||||
}
|
|
||||||
let userDbInfoAnon;
|
|
||||||
try {
|
|
||||||
const userDb = new PouchDb(name);
|
|
||||||
userDbInfoAnon = await userDb.info();
|
|
||||||
} catch (error) {
|
|
||||||
userDbInfoAnon = { error };
|
|
||||||
}
|
|
||||||
return { baseDbInfoAuth, baseDbInfoAnon, userDbInfo, userDbInfoAnon };
|
|
||||||
});
|
|
||||||
|
|
||||||
const submitHandler = async (values: any, context: any) => {
|
const submitHandler = async (values: any, context: any) => {
|
||||||
console.log({
|
console.log({
|
||||||
|
@ -91,9 +33,10 @@ const User: Component<Props> = (props) => {
|
||||||
values,
|
values,
|
||||||
context,
|
context,
|
||||||
});
|
});
|
||||||
const id = await save({ values, props });
|
const id = getValues()?._id ?? `user:${uuid()}`;
|
||||||
if (!props.values) {
|
await put(id, values, isNew());
|
||||||
navigate(`/user/${encodeURIComponent(id)}`);
|
if (isNew()) {
|
||||||
|
navigate(`/user/${id}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,42 +47,79 @@ const User: Component<Props> = (props) => {
|
||||||
const deleteHandler = async () => {
|
const deleteHandler = async () => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'User / deleteHandler',
|
caller: 'User / deleteHandler',
|
||||||
|
id: getValues()?._id,
|
||||||
props,
|
props,
|
||||||
});
|
});
|
||||||
await save({ props, values: { _deleted: true } });
|
await del(getValues()?._id);
|
||||||
navigate(`/user/`);
|
navigate(`/user/`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { form, data } = createForm({
|
const validationHandler = async (values: any) => {
|
||||||
|
let errors: any = {};
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
const { database, username, password } = credentials;
|
||||||
|
try {
|
||||||
|
const response = await fetch(database, { mode: 'cors' });
|
||||||
|
const dbStatus = await response.json();
|
||||||
|
if (!dbStatus.couchdb) {
|
||||||
|
errors.database = 'The URL is not a couchdb instance';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
errors.database = "Can't access the database";
|
||||||
|
}
|
||||||
|
if (!!errors.database) {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNew()) {
|
||||||
|
const authString = `${username}:${password}`;
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.set('Authorization', 'Basic ' + btoa(authString));
|
||||||
|
const response = await fetch(
|
||||||
|
`${database}/_users/org.couchdb.user:${values.username}`,
|
||||||
|
{
|
||||||
|
method: 'HEAD',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status === 200) {
|
||||||
|
errors.username = 'The user is already existing';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { form, data, setData, setInitialValues, reset } = createForm({
|
||||||
onSubmit: submitHandler,
|
onSubmit: submitHandler,
|
||||||
initialValues: props?.values,
|
extend: reporter(),
|
||||||
|
validate: validationHandler,
|
||||||
|
initialValues: getValues(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const dbCheckHandler = async () => {
|
createEffect(() => {
|
||||||
const result = await dbCheck({
|
console.log({ caller: 'user / createEffect', values: getValues() });
|
||||||
name: data('database'),
|
if (isNew()) {
|
||||||
auth: { username: data('username'), password: data('password') },
|
const credentials = adminCredentials();
|
||||||
});
|
if (!credentials) {
|
||||||
console.log({
|
return;
|
||||||
caller: 'User / dbCheckHandler',
|
|
||||||
props,
|
|
||||||
data: data(),
|
|
||||||
result,
|
|
||||||
});
|
|
||||||
if (result.baseDbInfoAnon.error) {
|
|
||||||
setStatus('baseError');
|
|
||||||
} else if (!result.userDbInfo.error) {
|
|
||||||
setStatus('OK');
|
|
||||||
} else if (
|
|
||||||
result.userDbInfoAnon.error.reason ===
|
|
||||||
'You are not authorized to access this db.'
|
|
||||||
) {
|
|
||||||
setStatus('passwordError');
|
|
||||||
} else {
|
|
||||||
setStatus('notFound');
|
|
||||||
}
|
}
|
||||||
setOpenDialog(true);
|
const { database } = credentials;
|
||||||
};
|
setData('database', database);
|
||||||
|
} else {
|
||||||
|
setInitialValues(getValues());
|
||||||
|
reset();
|
||||||
|
console.log({
|
||||||
|
caller: 'user / createEffect',
|
||||||
|
values: getValues(),
|
||||||
|
data: data(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const createUserHandler = async () => {
|
const createUserHandler = async () => {
|
||||||
console.log({
|
console.log({
|
||||||
|
@ -147,16 +127,16 @@ const User: Component<Props> = (props) => {
|
||||||
props,
|
props,
|
||||||
data: data(),
|
data: data(),
|
||||||
});
|
});
|
||||||
setOpenUserNamePasswordDialog(true);
|
// setOpenUserNamePasswordDialog(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'User ',
|
caller: 'User ',
|
||||||
props,
|
props,
|
||||||
|
values: getValues(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<form use:form>
|
<form use:form>
|
||||||
<TextField.Root>
|
<TextField.Root>
|
||||||
<TextField.Label>Mail address</TextField.Label>
|
<TextField.Label>Mail address</TextField.Label>
|
||||||
|
@ -177,10 +157,8 @@ const User: Component<Props> = (props) => {
|
||||||
name='database'
|
name='database'
|
||||||
required={true}
|
required={true}
|
||||||
placeholder='Database URL'
|
placeholder='Database URL'
|
||||||
|
readOnly={true}
|
||||||
/>
|
/>
|
||||||
<TextField.ErrorMessage>
|
|
||||||
Please provide a valid URL
|
|
||||||
</TextField.ErrorMessage>
|
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
<TextField.Root>
|
<TextField.Root>
|
||||||
<TextField.Label>User name</TextField.Label>
|
<TextField.Label>User name</TextField.Label>
|
||||||
|
@ -189,6 +167,7 @@ const User: Component<Props> = (props) => {
|
||||||
name='username'
|
name='username'
|
||||||
required={true}
|
required={true}
|
||||||
placeholder='user name'
|
placeholder='user name'
|
||||||
|
readOnly={!isNew()}
|
||||||
/>
|
/>
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
<TextField.Root>
|
<TextField.Root>
|
||||||
|
@ -200,64 +179,18 @@ const User: Component<Props> = (props) => {
|
||||||
placeholder='Password'
|
placeholder='Password'
|
||||||
autocomplete='off'
|
autocomplete='off'
|
||||||
/>
|
/>
|
||||||
<TextField.ErrorMessage>
|
|
||||||
Please provide a valid password
|
|
||||||
</TextField.ErrorMessage>
|
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={!!props.values}>
|
<Match when={!isNew()}>
|
||||||
<Button.Root type='submit'>Save</Button.Root>
|
<Button.Root type='submit'>Save</Button.Root>
|
||||||
<Button.Root onclick={deleteHandler}>Delete</Button.Root>
|
<Button.Root onclick={deleteHandler}>Delete</Button.Root>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={!props.values}>
|
<Match when={isNew()}>
|
||||||
<Button.Root type='submit'>Create</Button.Root>
|
<Button.Root type='submit'>Create</Button.Root>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
<Button.Root onclick={dbCheckHandler}>DB check</Button.Root>
|
|
||||||
<Button.Root onclick={cancelHandler}>Cancel</Button.Root>
|
<Button.Root onclick={cancelHandler}>Cancel</Button.Root>
|
||||||
</form>
|
</form>
|
||||||
<Dialog.Root isOpen={openDialog()} onOpenChange={setOpenDialog}>
|
|
||||||
<Dialog.Portal>
|
|
||||||
<Dialog.Overlay class='dialog__overlay' />
|
|
||||||
<div class='dialog__positioner'>
|
|
||||||
<Dialog.Content class='dialog__content'>
|
|
||||||
<div class='dialog__header'>
|
|
||||||
<Dialog.Title class='dialog__title'>
|
|
||||||
Database check
|
|
||||||
</Dialog.Title>
|
|
||||||
<Dialog.CloseButton class='dialog__close-button'>
|
|
||||||
X
|
|
||||||
</Dialog.CloseButton>
|
|
||||||
</div>
|
|
||||||
<Dialog.Description class='dialog__description'>
|
|
||||||
<Switch>
|
|
||||||
<Match when={status() === 'baseError'}>
|
|
||||||
The database address seems to be wrong !!
|
|
||||||
</Match>
|
|
||||||
<Match when={status() === 'OK'}>
|
|
||||||
The user is already existing.
|
|
||||||
</Match>
|
|
||||||
<Match when={status() === 'notFound'}>
|
|
||||||
<div>The user must be created.</div>
|
|
||||||
<Button.Root onclick={createUserHandler}>
|
|
||||||
Create user
|
|
||||||
</Button.Root>
|
|
||||||
</Match>
|
|
||||||
<Match when={status() === 'passwordError'}>
|
|
||||||
<div>
|
|
||||||
The user seems to exist but the password is wrong.
|
|
||||||
</div>
|
|
||||||
<Button.Root onclick={createUserHandler}>
|
|
||||||
Update password
|
|
||||||
</Button.Root>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</Dialog.Description>
|
|
||||||
</Dialog.Content>
|
|
||||||
</div>
|
|
||||||
</Dialog.Portal>
|
|
||||||
</Dialog.Root>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,20 @@
|
||||||
import { Button } from '@kobalte/core';
|
import { Button } from '@kobalte/core';
|
||||||
import { A } from '@solidjs/router';
|
import { A } from '@solidjs/router';
|
||||||
import PouchDb from 'pouchdb';
|
|
||||||
import { Component, createEffect, For } from 'solid-js';
|
import { Component, createEffect, For } from 'solid-js';
|
||||||
import { createServerAction$ } from 'solid-start/server';
|
|
||||||
import { useNavigate } from 'solid-start';
|
import { useNavigate } from 'solid-start';
|
||||||
|
|
||||||
interface Props {}
|
interface Props {
|
||||||
|
users: any;
|
||||||
|
}
|
||||||
|
|
||||||
const Users: Component<Props> = (props) => {
|
const Users: Component<Props> = (props) => {
|
||||||
|
const { users } = props;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [users, getUsers] = createServerAction$(
|
|
||||||
async (values: any) => {
|
|
||||||
const db = new PouchDb('.db');
|
|
||||||
const results = await db.allDocs({
|
|
||||||
include_docs: true,
|
|
||||||
startkey: 'user/',
|
|
||||||
endkey: 'user/\ufff0',
|
|
||||||
});
|
|
||||||
console.log({ caller: 'Users / serverAction', results });
|
|
||||||
return results.rows;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
getUsers();
|
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Users',
|
caller: 'Users',
|
||||||
users: users.result,
|
users: users(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -40,7 +26,7 @@ const Users: Component<Props> = (props) => {
|
||||||
<>
|
<>
|
||||||
<Button.Root onclick={newHandler}>New</Button.Root>
|
<Button.Root onclick={newHandler}>New</Button.Root>
|
||||||
<ul>
|
<ul>
|
||||||
<For each={users.result}>
|
<For each={users()}>
|
||||||
{(user: any) => {
|
{(user: any) => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Users / loop',
|
caller: 'Users / loop',
|
||||||
|
@ -48,9 +34,7 @@ const Users: Component<Props> = (props) => {
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<A href={encodeURIComponent(user.id)}>
|
<A href={user.id}>{user.doc.mail}</A>
|
||||||
{user.doc.mail}
|
|
||||||
</A>
|
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
import { headersWithAuth } from './headers-with-auth';
|
||||||
|
|
||||||
|
export const adminDbExists = async () => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
|
||||||
|
const headers = headersWithAuth();
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${database}/_dyomedea_users`, {
|
||||||
|
method: 'HEAD',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.error({ caller: 'dbExists', response });
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.status === 200;
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
import { headersWithAuth } from './headers-with-auth';
|
||||||
|
|
||||||
|
export const createAdminDb = async () => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
|
||||||
|
const headers = headersWithAuth();
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${database}/dyomedea_users`, {
|
||||||
|
method: 'PUT',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log({ caller: 'dbExists', response });
|
||||||
|
|
||||||
|
if (![200, 201].includes(response.status)) {
|
||||||
|
console.error({ caller: 'dbExists', response });
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
|
@ -1,11 +0,0 @@
|
||||||
export const put = async (params: { db: any; doc: any }) => {
|
|
||||||
const { db, doc } = params;
|
|
||||||
try {
|
|
||||||
const previous = await db.get(doc._id);
|
|
||||||
doc._rev = previous._rev;
|
|
||||||
} catch (error) {
|
|
||||||
console.error({ caller: 'put', doc, error });
|
|
||||||
}
|
|
||||||
console.log({ caller: 'put', doc });
|
|
||||||
db.put(doc);
|
|
||||||
};
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { put } from './put';
|
||||||
|
|
||||||
|
export const del = async (id: string) => {
|
||||||
|
const content = { _deleted: true };
|
||||||
|
return await put(id, content, false);
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
|
||||||
|
export const getUrl = (id: string) => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
return `${database}/dyomedea_users/${id}`;
|
||||||
|
};
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
import { headersWithAuth } from './headers-with-auth';
|
||||||
|
|
||||||
|
export const get = async (id: string) => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
|
||||||
|
const headers = headersWithAuth();
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${database}/dyomedea_users/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
|
||||||
|
export const headersWithAuth = () => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { username, password } = credentials;
|
||||||
|
const authString = `${username}:${password}`;
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.set('Authorization', 'Basic ' + btoa(authString));
|
||||||
|
return headers;
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { adminCredentials } from '~/components/credentials';
|
||||||
|
import { get } from './get';
|
||||||
|
import { getUrl } from './get-url';
|
||||||
|
import { headersWithAuth } from './headers-with-auth';
|
||||||
|
|
||||||
|
export const put = async (id: string, content: any, isNew: boolean = false) => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
|
||||||
|
if (!isNew) {
|
||||||
|
const previous = await get(id);
|
||||||
|
content._rev = previous._rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = headersWithAuth();
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
headers.set('Content-type', 'application/json; charset=UTF-8');
|
||||||
|
|
||||||
|
const response = await fetch(getUrl(id), {
|
||||||
|
method: 'PUT',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(content),
|
||||||
|
});
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
};
|
|
@ -1,36 +1,30 @@
|
||||||
import { useParams } from 'solid-start';
|
import { useParams } from 'solid-start';
|
||||||
import { createServerAction$ } from 'solid-start/server';
|
|
||||||
import PouchDb from 'pouchdb';
|
|
||||||
import User from '~/components/user';
|
import User from '~/components/user';
|
||||||
import { createEffect, Show } from 'solid-js';
|
import { createEffect, createSignal } from 'solid-js';
|
||||||
|
import { adminCredentials, CheckCredentials } from '~/components/credentials';
|
||||||
|
import { get } from '~/lib/get';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const params = useParams();
|
const { id } = useParams();
|
||||||
const [user, getUser] = createServerAction$(
|
const [user, setUser] = createSignal();
|
||||||
async (id: string) => {
|
|
||||||
const db = new PouchDb('.db');
|
|
||||||
const result = await db.get(id);
|
|
||||||
console.log({ caller: 'Users / serverAction', result });
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
getUser(decodeURIComponent(params.id));
|
createEffect(async () => {
|
||||||
|
if (!user()) {
|
||||||
createEffect(() => {
|
setUser(await get(id));
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Users/[id]',
|
caller: '/routes/user/[id].ts / createEffect',
|
||||||
params,
|
user: user(),
|
||||||
user: user.result,
|
adminCredentials: adminCredentials(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<h1>User</h1>
|
<h1>User</h1>
|
||||||
<Show when={!user.pending} fallback={<>Loading...</>}>
|
<CheckCredentials>
|
||||||
<User values={user.result} />
|
<User values={user} />
|
||||||
</Show>
|
</CheckCredentials>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,21 +1,64 @@
|
||||||
import { createEffect, Show } from 'solid-js';
|
import { createEffect } from 'solid-js';
|
||||||
import Credentials, { adminCredentials } from '~/components/credentials';
|
import { createRouteData, refetchRouteData, useRouteData } from 'solid-start';
|
||||||
|
import { adminCredentials, CheckCredentials } from '~/components/credentials';
|
||||||
import Users from '~/components/users';
|
import Users from '~/components/users';
|
||||||
|
import { adminDbExists } from '~/lib/admin-db-exists';
|
||||||
|
import { createAdminDb } from '~/lib/create-admin-db';
|
||||||
|
import { headersWithAuth } from '~/lib/headers-with-auth';
|
||||||
|
|
||||||
|
export function routeData() {
|
||||||
|
return createRouteData(async () => {
|
||||||
|
if (!(await adminDbExists())) {
|
||||||
|
await createAdminDb();
|
||||||
|
}
|
||||||
|
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { database } = credentials;
|
||||||
|
const headers = headersWithAuth();
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
headers.set('Content-type', 'application/json; charset=UTF-8');
|
||||||
|
const response = await fetch(`${database}/dyomedea_users/_all_docs`, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
include_docs: true,
|
||||||
|
startkey: 'user:',
|
||||||
|
endkey: 'user:\ufff0',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = await response.json();
|
||||||
|
console.log({ caller: 'user route / routeData', results });
|
||||||
|
return results.rows;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
const credentials = adminCredentials();
|
||||||
|
if (!!credentials) {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'user/index / createEffect',
|
caller: 'routes/user/index.tsx / createEffect',
|
||||||
adminCredentials: adminCredentials(),
|
adminCredentials: credentials,
|
||||||
});
|
});
|
||||||
|
refetchRouteData();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
const users = useRouteData<typeof routeData>();
|
||||||
|
// const users = routeData();
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<h1>Users</h1>
|
<h1>Users</h1>
|
||||||
<Show when={!!adminCredentials()} fallback={<Credentials />}>
|
<CheckCredentials>
|
||||||
<Users />
|
<Users users={users} />
|
||||||
</Show>
|
</CheckCredentials>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import User from "~/components/user";
|
import { CheckCredentials } from '~/components/credentials';
|
||||||
|
import User from '~/components/user';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<h1>New user</h1>
|
<h1>New user</h1>
|
||||||
|
<CheckCredentials>
|
||||||
<User />
|
<User />
|
||||||
|
</CheckCredentials>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue