import { createForm } from '@felte/solid'; import { Component, createSignal, Index, Match, onMount, Show, Switch, } from 'solid-js'; import { TextField, Button, Progress } from '@kobalte/core'; import reporter from '@felte/reporter-tippy'; import './style.css'; import { A, useNavigate } from 'solid-start'; import { adminCredentials } from '../credentials'; import { put } from '~/lib/put'; import { del } from '~/lib/del'; import { isFunction } from 'lodash'; import { userId } from '~/lib/user-id'; import { userExists } from '~/lib/user-exists'; import { update } from '~/lib/update'; import { replicationDocument } from '~/lib/replication-document'; import { get } from '~/lib/get'; import { v4 as uuid } from 'uuid'; interface Props { values?: () => any; } const User: Component = (props) => { const navigate = useNavigate(); const [progress, setProgress] = createSignal(-1); const defaultValues = () => ({}); const values = props.values ?? defaultValues; const [previousSubscriptions, setPreviousSubscriptions] = createSignal( values().subscriptions ?? [] ); const credentials = adminCredentials(); const { database } = credentials || { database: null }; const isNew = () => !isFunction(props?.values); const getValues = () => { if (isNew()) { return { database, subscriptions: [], token: uuid() }; } return { token: uuid(), subscriptions: [], ...values() }; }; const invitationLink = (type = 'https') => { // TODO: make these URLs configurable if (type === 'https') { const configUrl = `https://admin.dyomedea.app/api/conf/${ getValues().token }`; return `https://web.dyomedea.app#${btoa(configUrl)}`; } else { const configUrl = `https://admin.dyomedea.app/api/conf/${ getValues().token }`; return `geo:?invitation=${btoa(configUrl)}`; } }; const submitHandler = async (values: any, context: any) => { console.log({ caller: 'User / submitHandler', props, values, context, }); if (!database) { return; } const { username } = values; setProgress(0); const id = getValues()?._id ?? userId(username, values.database); await put(id, values, isNew()); const couchUserId = `org.couchdb.user:${username}`; const userDoc = { _id: couchUserId, name: username, password: values.password, type: 'user', roles: [], }; await put(couchUserId, userDoc, isNew(), '_users'); setProgress(1); const updatedSubscriptions = values.subscriptions ?? []; const isIn = (username: string, subs: any[]) => { for (let i = 0; i < subs.length; i++) { let sub = subs[i]; if (username === sub.username) { return true; } } return false; }; console.log({ caller: 'User / submitHandler', previousSubscriptions: previousSubscriptions(), updatedSubscriptions, }); const addSubscriptionFactory = (subscriptionUserName: string) => (userDocument: any) => { const subscriptions = userDocument.subscriptions || []; subscriptions.push({ username, direction: '' }); userDocument.subscriptions = subscriptions; return { username: subscriptionUserName, ...userDocument }; }; const removeSubscriptionFactory = (subscriptionUserName: string) => (userDocument: any) => { const subscriptions = userDocument.subscriptions || []; userDocument.subscriptions = subscriptions.filter( (subscription: any) => subscription.username !== username ); return { username: subscriptionUserName, ...userDocument }; }; const defaultUserDocument = { database, }; const currentUserId = userId(data('username'), data('database')); const credentials = adminCredentials(); const adminUser = credentials?.username || ''; for (let i = 0; i < updatedSubscriptions.length; i++) { let subscription = updatedSubscriptions[i]; if (!isIn(subscription.username, previousSubscriptions())) { await update( userId(subscription.username, database), addSubscriptionFactory(subscription.username), defaultUserDocument ); const otherUserId = userId(subscription.username, data('database')); const otherUserPassword = (await get(otherUserId)).password; let repDocument = replicationDocument( currentUserId, data('password'), otherUserId, otherUserPassword, adminUser ); await put(repDocument._id, repDocument, false, '_replicator'); repDocument = replicationDocument( otherUserId, otherUserPassword, currentUserId, data('password'), adminUser ); await put(repDocument._id, repDocument, false, '_replicator'); console.log({ caller: 'User / submitHandler / new subscription', username: subscription.username, }); } } setProgress(2); for (let i = 0; i < previousSubscriptions().length; i++) { let subscription = previousSubscriptions()[i]; if (!isIn(subscription.username, updatedSubscriptions)) { await update( userId(subscription.username, database), removeSubscriptionFactory(subscription.username), defaultUserDocument ); const otherUserId = userId(subscription.username, data('database')); await del(`${currentUserId}=>${otherUserId}`, '_replicator'); await del(`${otherUserId}=>${currentUserId}`, '_replicator'); console.log({ caller: 'User / submitHandler / deleted subscription', username: subscription.username, }); } } setProgress(3); setInitialValues(values); setPreviousSubscriptions(values.subscriptions); setIsDirty(false); setProgress(-1); navigate(`/user/${id}`); }; const cancelHandler = () => { navigate(`/user/`); }; const deleteHandler = async () => { console.log({ caller: 'User / deleteHandler', id: getValues()?._id, props, }); await del(getValues()?._id); navigate(`/user/`); }; 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; } const subscriptions = values.subscriptions ?? []; for (let i = 0; i < subscriptions.length; i++) { let subscription = subscriptions[i]; if ( !!subscription.username && !(await userExists(subscription.username)) ) { if (!errors.subscriptions) { errors.subscriptions = []; } errors.subscriptions[i] = { username: "User doesn't exist" }; } } if (isNew()) { if (await userExists(values.username)) { errors.username = 'The user is already existing'; } } console.log({ caller: 'Users / validationHandler', values, errors }); return errors; }; const { form, data, setData, setIsDirty, setInitialValues, reset, addField, unsetField, isDirty, isValid, } = createForm({ onSubmit: submitHandler, extend: reporter(), validate: validationHandler, initialValues: getValues(), }); const createUserHandler = async () => { console.log({ caller: 'User / createUserHandler', props, data: data(), }); // setOpenUserNamePasswordDialog(true); }; const subscriptions = () => data('subscriptions'); function removeSubscription(index: number) { return () => { unsetField(`subscriptions.${index}`); setIsDirty(true); }; } function addSubscription(index?: number) { return () => { addField(`subscriptions`, { username: '', direction: '' }, index); setIsDirty(true); }; } console.log({ caller: 'User ', props, values: getValues(), data: data(), }); return ( <> = 0}> `${value} of ${max} tasks completed` } class='progress' >
Processing...

{userId(data('username'), data('database'))}

Invitations : https , geo

Mail address Please provide a valid URL Database User name Password {(_, index) => ( )}
User name
Save Delete Create Back
); }; export default User;