Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

URL subjects + Email support + subdomains #1035

Open
wants to merge 51 commits into
base: develop
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
bd6288c
Register endpoint, URLs #288 #48gister Endpoint and true URLs
joepio Aug 22, 2024
430e136
Fix some tests
joepio Aug 22, 2024
40e88c0
WIP Path URL
joepio Aug 22, 2024
01085e5
#518 Fix cargo in CI
joepio Aug 22, 2024
530a81a
Fix tests
joepio Aug 22, 2024
ec60fbd
Debug for endpoints
joepio Aug 22, 2024
27787b4
Fix URL refactor paths endpoints #502
joepio Aug 22, 2024
45dc543
URL refactor
joepio Aug 22, 2024
f451311
Add rust vscode extension suggestions
joepio Aug 22, 2024
ef3c650
Fix pnpm tasks
joepio Aug 22, 2024
37aa7a1
Improve register endpoint, WIP
joepio Aug 22, 2024
c4772da
Rebased
joepio Aug 22, 2024
fd75795
Update changelog
joepio Aug 22, 2024
c1f8de7
Custom .env parsing, smtp server opts
joepio Aug 22, 2024
ebaad5a
Register endpoint, mail, tokens, #489 #254 #544
joepio Aug 22, 2024
48214ed
WIP
joepio Aug 22, 2024
156ab34
Public key reset endpoint WIP
joepio Aug 22, 2024
3998b10
#502 fix path confirm email
joepio Aug 22, 2024
d05e8e6
Check uniqueness username earlier #489
joepio Aug 22, 2024
c0f293f
Refactor endpoints, update JSON
joepio Aug 22, 2024
e87ff7a
Improve check_append error #558
joepio Aug 22, 2024
cdebc02
556 constrain URLs
joepio Aug 22, 2024
a63f406
Store.tpf public for tests
joepio Aug 22, 2024
412aa9e
import_file test failing on macos #564
joepio Aug 22, 2024
61c7415
Throw error on trailing slash server URL #566
joepio Aug 22, 2024
b87fc22
Fix cookies subject in search
joepio Aug 22, 2024
2e43ea0
Set max chars for meta tags
joepio Aug 22, 2024
107ab3a
Cleanup, imports
joepio Aug 22, 2024
a2c68f5
Fix rebase issues
joepio Aug 22, 2024
fc27524
Use get_subject
joepio Aug 22, 2024
070265d
Do not add `register` endpoint if there is no SMTP server
joepio Aug 22, 2024
d09b138
Fix issues?
joepio Aug 22, 2024
dcaa9d7
Add register form + email confirm #640 #544 #489 #276
joepio Aug 22, 2024
3afed63
502-wildcard-subdomain:
joepio Aug 22, 2024
87c85b3
Fix errors
joepio Aug 22, 2024
2a5f0f5
Migrate trailing slash base URLs #895
joepio Aug 22, 2024
68ad702
WIP fix issues
joepio Aug 22, 2024
9defb09
WIP
joepio Aug 22, 2024
9008db3
Fix build
joepio Aug 22, 2024
2bc5651
Add "report issue" button in error component #911
joepio Aug 22, 2024
904c481
Slow build.rs / rust analyzer #913
joepio Aug 22, 2024
d725f82
Make RegisterSignIn work
joepio Aug 22, 2024
8b14eb3
AsyncMarkdownEditor and MarkdownWrapper should share styles #917
joepio Aug 22, 2024
e0033db
Fix history page
joepio Aug 22, 2024
3a006f8
Improve server FAQ
joepio Aug 22, 2024
ad88966
Clippy fixes
joepio Aug 23, 2024
2e82803
Fix slow build.rs / rust analyzer #913
joepio Aug 23, 2024
c69e268
Fix initialize bug
joepio Aug 23, 2024
02d76d3
Fix issues rebase
joepio Oct 7, 2024
58cd95a
Simplified DB init
joepio Feb 4, 2025
1255691
Remove duplicate email
joepio Feb 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make RegisterSignIn work
joepio committed Jan 30, 2025
commit d725f829022bafac51bfa4f6b0052cccff0f135e
3 changes: 1 addition & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@
"styled-components.vscode-styled-components",
"svelte.svelte-vscode",
"vadimcn.vscode-lldb",
"rust-lang.rust-analyzer",
"serayuzgur.crates"
"rust-lang.rust-analyzer"
]
}
6 changes: 5 additions & 1 deletion browser/data-browser/src/components/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -33,7 +33,11 @@ export function ConfirmationDialog({
bindShow,
theme = ConfirmationDialogTheme.Default,
}: React.PropsWithChildren<ConfirmationDialogProps>): JSX.Element {
const [dialogProps, showDialog, hideDialog] = useDialog({
const {
dialogProps,
show: showDialog,
close: hideDialog,
} = useDialog({
bindShow,
onCancel,
onSuccess: onConfirm,
23 changes: 14 additions & 9 deletions browser/data-browser/src/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ import { useDialogGlobalContext } from './DialogGlobalContextProvider';
import { DIALOG_CONTENT_CONTAINER } from '../../helpers/containers';

export interface InternalDialogProps {
show: boolean;
/** Is the Dialog visible */
isVisible: boolean;
onClose: (success: boolean) => void;
onClosed: () => void;
width?: CSS.Property.Width;
@@ -81,17 +82,17 @@ export function Dialog(props: React.PropsWithChildren<InternalDialogProps>) {

const InnerDialog: React.FC<React.PropsWithChildren<InternalDialogProps>> = ({
children,
show,
isVisible,
width,
onClose,
onClosed,
}) => {
const dialogRef = useRef<HTMLDialogElement>(null);
const innerDialogRef = useRef<HTMLDivElement>(null);
const { hasOpenInnerPopup } = useDialogTreeContext();
const { isTopLevel } = useDialogGlobalContext(show);
const { isTopLevel } = useDialogGlobalContext(isVisible);

useControlLock(show);
useControlLock(isVisible);

const cancelDialog = useCallback(() => {
onClose(false);
@@ -123,22 +124,26 @@ const InnerDialog: React.FC<React.PropsWithChildren<InternalDialogProps>> = ({
() => {
cancelDialog();
},
{ enabled: show && !hasOpenInnerPopup && isTopLevel },
{ enabled: isVisible && !hasOpenInnerPopup && isTopLevel },
);

// When closing the `data-closing` attribute must be set before rendering so the animation has started when the regular useEffect is called.
useLayoutEffect(() => {
if (!show && dialogRef.current && dialogRef.current.hasAttribute('open')) {
if (
!isVisible &&
dialogRef.current &&
dialogRef.current.hasAttribute('open')
) {
dialogRef.current.setAttribute('data-closing', 'true');
}
}, [show]);
}, [isVisible]);

useEffect(() => {
if (!dialogRef.current) {
return;
}

if (show) {
if (isVisible) {
if (!dialogRef.current.hasAttribute('open'))
// @ts-ignore
dialogRef.current.showModal();
@@ -153,7 +158,7 @@ const InnerDialog: React.FC<React.PropsWithChildren<InternalDialogProps>> = ({
onClosed();
}, ANIM_MS);
}
}, [show, onClosed]);
}, [isVisible, onClosed]);

return (
<StyledDialog
23 changes: 12 additions & 11 deletions browser/data-browser/src/components/Dialog/useDialog.tsx
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@ export type UseDialogReturnType = {
/** Function to show the dialog */
show: () => void;
/** Function to close the dialog */
close: (success?: boolean) => void,
/** Boolean indicating wether the dialog is currently open */
close: (success?: boolean) => void;
/** Whether the dialog is currently open */
isOpen: boolean;
};

@@ -25,26 +25,27 @@ export function useDialog<E extends HTMLElement>(
): UseDialogReturnType {
const { bindShow, onCancel, onSuccess, triggerRef } = options ?? {};

const [showDialog, setShowDialog] = useState(false);
const [visible, setVisible] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [isVisible, setIsVisible] = useState(false);
const [wasSuccess, setWasSuccess] = useState(false);

const show = useCallback(() => {
document.body.setAttribute('inert', '');
setShowDialog(true);
setVisible(true);
setIsVisible(true);
setIsOpen(true);
bindShow?.(true);
}, []);

const close = useCallback((success = false) => {
setWasSuccess(success);
setShowDialog(false);
setIsVisible(false);
// The 'isOpen' will be set to false by handleClosed after the animation
}, []);

const handleClosed = useCallback(() => {
document.body.removeAttribute('inert');
bindShow?.(false);
setVisible(false);
setIsOpen(false);

if (wasSuccess) {
onSuccess?.();
@@ -60,12 +61,12 @@ export function useDialog<E extends HTMLElement>(
/** Props that should be passed to a {@link Dialog} component. */
const dialogProps = useMemo<InternalDialogProps>(
() => ({
show: showDialog,
isVisible,
onClose: close,
onClosed: handleClosed,
}),
[showDialog, close, handleClosed],
[isVisible, close, handleClosed],
);

return [dialogProps, show, close, visible];
return { dialogProps, show, close, isOpen };
}
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ export function ParentPickerDialog({
}: ParentPickerDialogProps): React.JSX.Element {
const [selected, setSelected] = useState<string>();

const [dialogProps, show, close, isOpen] = useDialog({
const { dialogProps, show, close, isOpen } = useDialog({
onCancel,
bindShow: onOpenChange,
});
35 changes: 14 additions & 21 deletions browser/data-browser/src/components/RegisterSignIn.tsx
Original file line number Diff line number Diff line change
@@ -5,8 +5,7 @@ import {
DialogTitle,
useDialog,
} from './Dialog';
import React, { FormEvent, useCallback, useEffect, useState } from 'react';
import { useSettings } from '../helpers/AppSettings';
import { FormEvent, useCallback, useEffect, useState } from 'react';
import { Button } from './Button';
import {
addPublicKey,
@@ -22,16 +21,15 @@ import { Row } from './Row';
import { ErrorLook } from './ErrorLook';
import { SettingsAgent } from './SettingsAgent';

interface RegisterSignInProps {
// URL where to send the user to after successful registration
redirect?: string;
}

/** What is currently showing */
enum PageStateOpts {
/** Start state, select register or sign in */
none,
/** Enter Secret*/
signIn,
/** Register new Email address */
register,
/** Reset existing email, send Secret reset email link */
reset,
mailSentRegistration,
mailSentAddPubkey,
@@ -41,22 +39,17 @@ enum PageStateOpts {
* Two buttons: Register / Sign in.
* Opens a Dialog / Modal with the appropriate form.
*/
export function RegisterSignIn({
children,
}: React.PropsWithChildren<RegisterSignInProps>): JSX.Element {
export function RegisterSignIn(): JSX.Element {
const { dialogProps, show, close } = useDialog();
const { agent } = useSettings();
const [pageState, setPageState] = useState<PageStateOpts>(PageStateOpts.none);
const [email, setEmail] = useState('');
const { emailRegister } = useServerSupports();

if (agent) {
return <>{children}</>;
} else if (!emailRegister) {
if (!emailRegister) {
return (
<>
<SettingsAgent />
<ErrorLook>No e-mail support on this server...</ErrorLook>
<ErrorLook>No email support on this server...</ErrorLook>
</>
);
}
@@ -82,7 +75,7 @@ export function RegisterSignIn({
Sign In
</Button>
</Row>
{/* <Dialog {...dialogProps}>
<Dialog {...dialogProps}>
{pageState === PageStateOpts.register && (
<Register
setPageState={setPageState}
@@ -111,10 +104,10 @@ export function RegisterSignIn({
<MailSentConfirm
email={email}
close={close}
message={'Click that link to create a new PassPhrase.'}
message={'Click that link to create a new Secret.'}
/>
)}
</Dialog> */}
</Dialog>
</>
);
}
@@ -135,7 +128,7 @@ function Reset({ email, setEmail, setPageState }) {
return (
<>
<DialogTitle>
<h1>Reset your PassKey</h1>
<h1>Reset your Secret</h1>
</DialogTitle>
<DialogContent>
<p>
@@ -145,7 +138,7 @@ function Reset({ email, setEmail, setPageState }) {
</p>
<EmailField
email={email}
setEmail={(e: any) => {
setEmail={(e: unknown) => {
setErr(undefined);
setEmail(e);
}}
@@ -277,7 +270,7 @@ function SignIn({ setPageState }) {
Register
</Button>
<Button subtle onClick={() => setPageState(PageStateOpts.reset)}>
I lost my passphrase
I lost my Secret
</Button>
</DialogActions>
</>
6 changes: 3 additions & 3 deletions browser/data-browser/src/components/SettingsAgent.tsx
Original file line number Diff line number Diff line change
@@ -108,9 +108,9 @@ export const SettingsAgent: React.FunctionComponent = () => {
return (
<form>
<Field
label={agent ? 'Passphrase' : 'Enter your Passphrase'}
label={agent ? 'Secret' : 'Enter your Secret'}
helper={
"The Agent Passphrase is a secret, long string of characters that encodes both the Subject and the Private Key. You can think of it as a combined username + password. Store it safely, and don't share it with others."
"The Secret is a long string of characters that encodes both the Subject and the Private Key. You can think of it as a combined username + password. Store it safely, and don't share it with others."
}
error={error}
>
@@ -124,7 +124,7 @@ export const SettingsAgent: React.FunctionComponent = () => {
id='current-password'
autoComplete='current-password'
spellCheck='false'
placeholder='Paste your Passphrase'
placeholder='Paste your Secret'
/>
<ButtonInput
type='button'
Original file line number Diff line number Diff line change
@@ -34,7 +34,11 @@ export function FilePickerDialog({
noUpload = false,
}: FilePickerProps): React.JSX.Element {
const { drive } = useSettings();
const [dialogProps, showDialog, closeDialog] = useDialog({
const {
dialogProps,
show: showDialog,
close: closeDialog,
} = useDialog({
bindShow: onShowChange,
});

Original file line number Diff line number Diff line change
@@ -44,7 +44,10 @@ export const NewArticleDialog: FC<CustomResourceDialogProps> = ({
onClose();
}, [name, createResourceAndNavigate, onClose, parent]);

const [dialogProps, show, hide] = useDialog({ onSuccess, onCancel: onClose });
const { dialogProps, show, close } = useDialog({
onSuccess,
onCancel: onClose,
});

const onNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
@@ -69,7 +72,7 @@ export const NewArticleDialog: FC<CustomResourceDialogProps> = ({
<form
onSubmit={(e: FormEvent) => {
e.preventDefault();
hide(true);
close(true);
}}
>
<Field required label='Title'>
@@ -89,10 +92,10 @@ export const NewArticleDialog: FC<CustomResourceDialogProps> = ({
</form>
</DialogContent>
<DialogActions>
<Button onClick={() => hide(false)} subtle>
<Button onClick={() => close(false)} subtle>
Cancel
</Button>
<Button onClick={() => hide(true)} disabled={!valid}>
<Button onClick={() => close(true)} disabled={!valid}>
Create
</Button>
</DialogActions>
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ export const NewCollectionDialog: FC<CustomResourceDialogProps> = ({
const [valueFilter, setValue] = useState<string | undefined>();
const [propertyFilter, setProperty] = useState<string | undefined>();

const [dialogProps, show, hide] = useDialog({ onCancel: onClose });
const { dialogProps, show, close } = useDialog({ onCancel: onClose });

const createResourceAndNavigate = useCreateAndNavigate();

@@ -91,7 +91,7 @@ export const NewCollectionDialog: FC<CustomResourceDialogProps> = ({
</form>
</DialogContent>
<DialogActions>
<Button onClick={() => hide(false)} subtle>
<Button onClick={() => close(false)} subtle>
Cancel
</Button>
<Button onClick={onDone} disabled={!propertyFilter && !valueFilter}>
Original file line number Diff line number Diff line change
@@ -91,7 +91,11 @@ export const NewDriveDialog: FC<CustomResourceDialogProps> = ({
onClose();
}, [name, createAndNavigate, onClose, parent, setDrive, store]);

const [dialogProps, show, hide] = useDialog({ onSuccess, onCancel: onClose });
const {
dialogProps,
show,
close: hide,
} = useDialog({ onSuccess, onCancel: onClose });

useEffect(() => {
show();
Original file line number Diff line number Diff line change
@@ -41,7 +41,11 @@ export const NewOntologyDialog: FC<CustomResourceDialogProps> = ({
onClose();
}, [shortname, createResourceAndNavigate, onClose, parent]);

const [dialogProps, show, hide] = useDialog({ onSuccess, onCancel: onClose });
const {
dialogProps,
show,
close: hide,
} = useDialog({ onSuccess, onCancel: onClose });

const onShortnameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = stringToSlug(e.target.value);
Original file line number Diff line number Diff line change
@@ -89,7 +89,12 @@ export const NewTableDialog: FC<NewTableDialogProps> = ({
createResourceAndNavigate,
]);

const [dialogProps, show, hide, isOpen] = useDialog({ onCancel, onSuccess });
const {
dialogProps,
show,
close: hide,
isOpen,
} = useDialog({ onCancel, onSuccess });

useEffect(() => {
show();
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import styled from 'styled-components';
import { NewFormDialog } from './NewForm/NewFormDialog';
import { DropdownInput } from './ResourceSelector/DropdownInput';

interface ResourceSelectorProps {
export interface ResourceSelectorProps {
/**
* Whether a certain type of Class is required here. Pass the URL of the
* class. Is used for constructing a list of options.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useMemo, memo, useContext } from 'react';
import { memo, useContext, useMemo, useState } from 'react';
import { Dialog, useDialog } from '../../Dialog';
import { useSettings } from '../../../helpers/AppSettings';
import { css, styled } from 'styled-components';
@@ -103,7 +103,12 @@ export const ResourceSelector = memo(function ResourceSelector({
const [classSelectorOpen, setClassSelectorOpen] = useState(false);
const [titleProp, setTitleProp] = useState<string>();

const [dialogProps, showDialog, closeDialog, isDialogOpen] = useDialog({
const {
dialogProps,
show: showDialog,
close: closeDialog,
isOpen: isDialogOpen,
} = useDialog({
onSuccess: () => {
setSubject(pickedSubject);
},
12 changes: 6 additions & 6 deletions browser/data-browser/src/routes/ConfirmEmail.tsx
Original file line number Diff line number Diff line change
@@ -67,13 +67,13 @@ const ConfirmEmail: React.FunctionComponent = () => {
}

if (secret) {
return <SavePassphrase secret={secret} destination={destinationToGo} />;
return <SaveSecret secret={secret} destination={destinationToGo} />;
}

return <ContainerNarrow>Verifying token...</ContainerNarrow>;
};

function SavePassphrase({ secret, destination }) {
function SaveSecret({ secret, destination }) {
const [copied, setCopied] = useState(false);

function copyToClipboard() {
@@ -84,9 +84,9 @@ function SavePassphrase({ secret, destination }) {

return (
<ContainerNarrow>
<h1>Mail confirmed, please save your passphrase</h1>
<h1>Mail confirmed, please save your Secret</h1>
<p>
Your Passphrase is like your password. Never share it with anyone. Use a
Your Secret is like your password. Never share it with anyone. Use a
password manager like{' '}
<a href='https://bitwarden.com/' target='_blank' rel='noreferrer'>
BitWarden
@@ -96,10 +96,10 @@ function SavePassphrase({ secret, destination }) {
<CodeBlockStyled wrapContent>{secret}</CodeBlockStyled>
{copied ? (
<a href={destination} target='_blank' rel='noreferrer'>
{"I've saved my PassPhrase, open my new Drive!"}
{"I've saved my Secret, open my new Drive!"}
</a>
) : (
<Button onClick={copyToClipboard}>Copy Passphrase</Button>
<Button onClick={copyToClipboard}>Copy Secret</Button>
)}
</ContainerNarrow>
);
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ export function HistoryMobileView({
onSelectVersion,
onVersionAccept,
}: HistoryViewProps) {
const [dialogProps, showDialog, closeDialog] = useDialog();
const { dialogProps, show: showDialog, close: closeDialog } = useDialog();

const handleVersionSelect = useCallback((version: Version) => {
onSelectVersion(version);
15 changes: 15 additions & 0 deletions browser/data-browser/src/routes/Sandbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Button } from '../components/Button';
import { ContainerFull } from '../components/Containers';
import {
Dialog,
DialogContent,
DialogTitle,
useDialog,
} from '../components/Dialog';

export function Sandbox(): JSX.Element {
const { dialogProps, show, isOpen } = useDialog();

return (
<main>
<ContainerFull>
@@ -9,6 +18,12 @@ export function Sandbox(): JSX.Element {
Welcome to the sandbox. This is a place to test components in
isolation.
</p>
<p>{isOpen ? 'TRUE' : 'FALSE'}</p>
<Button onClick={show}>Button</Button>
<Dialog {...dialogProps}>
<DialogTitle>Title</DialogTitle>
<DialogContent>Content</DialogContent>
</Dialog>
</ContainerFull>
</main>
);
2 changes: 0 additions & 2 deletions browser/data-browser/src/routes/SettingsAgent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as React from 'react';

import { useSettings } from '../helpers/AppSettings';
import { Button } from '../components/Button';
import { Margin } from '../components/Card';
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ export function ResourceCodeUsageDialog({
bindShow,
}: ResourceCodeUsageDialogProps): React.JSX.Element {
const resource = useResource(subject);
const [dialogProps, show, hide, isOpen] = useDialog({ bindShow });
const { dialogProps, show, close: hide, isOpen } = useDialog({ bindShow });

useEffect(() => {
if (open) {
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ interface CreateInstanceButtonProps {
export function CreateInstanceButton({ ontology }: CreateInstanceButtonProps) {
const [classSelectorActive, setClassSelectorActive] = useState(false);
const [classSubject, setClassSubject] = useState<string | undefined>();
const [dialogProps, show, close, isOpen] = useDialog({
const { dialogProps, show, close, isOpen } = useDialog({
onSuccess: () => {
setClassSubject(undefined);
ontology.save();
Original file line number Diff line number Diff line change
@@ -29,7 +29,12 @@ export function NewClassButton({ resource }: NewClassButtonProps): JSX.Element {

const subject = subjectForClass(resource, inputValue);

const [dialogProps, show, hide, isOpen] = useDialog({
const {
dialogProps,
show,
close: hide,
isOpen,
} = useDialog({
onSuccess: async () => {
const createdClass = await newClass(inputValue, resource, store);
const id = toAnchorId(createdClass);
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ export function PropertyLineWrite({
const resource = useResource(subject);
const shortnameProp = useProperty(core.properties.shortname);
const descriptionProp = useProperty(core.properties.description);
const [dialogProps, show, hide] = useDialog();
const { dialogProps, show, close: hide } = useDialog();
const [canEdit] = useCanWrite(resource);

const { hasProperty } = useOntologyContext();
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ export function PropertyWriteDialog({

return (
<Dialog {...dialogProps} width='min(40rem, 90vw)'>
{dialogProps.show && (
{dialogProps.isVisible && (
<>
<DialogTitle>
<InputSwitcher
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ export function EditPropertyDialog({
resource.save();
}, [resource]);

const [dialogProps, show, hide] = useDialog({ bindShow, onSuccess });
const { dialogProps, show, close: hide } = useDialog({ bindShow, onSuccess });

useEffect(() => {
if (showDialog) {
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ export function ExternalPropertyDialog({
urls.properties.recommends,
{ commit: true },
);
const [dialogProps, show, hide] = useDialog({ bindShow });
const { dialogProps, show, close: hide } = useDialog({ bindShow });

const onAddClick = () => {
if (subject) {
Original file line number Diff line number Diff line change
@@ -136,7 +136,11 @@ export function NewPropertyDialog({
setResource(null);
}, [resource, store, tableClassResource, pushProp]);

const [dialogProps, show, hide] = useDialog({
const {
dialogProps,
show,
close: hide,
} = useDialog({
bindShow,
onCancel: handleUserCancelAction,
onSuccess: handleUserSuccessAction,
4 changes: 2 additions & 2 deletions browser/e2e/tests/e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -65,9 +65,9 @@ test.describe('data-browser', async () => {
// Sign out
await openAgentPage(page);
await page.click('[data-test="sign-out"]');
await expect(page.locator('text=Enter your Agent secret')).toBeVisible();
await expect(page.locator('text=Enter your Secret')).toBeVisible();
await page.reload();
await expect(page.locator('text=Enter your Agent secret')).toBeVisible();
await expect(page.locator('text=Enter your Secret')).toBeVisible();
});

test('sign up and edit document atomicdata.dev', async ({ page }) => {
56 changes: 24 additions & 32 deletions browser/lib/src/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Agent } from './agent.js';
import type { HeadersObject } from './client.js';
import { generateKeyPair, getTimestampNow, signToBase64 } from './commit.js';
import { core } from './ontologies/core.js';
import type { Store } from './store.js';
import type { Resource } from './resource.js';
import { core } from './ontologies/core.js';

/** Returns a JSON-AD resource of an Authentication */
export async function createAuthentication(subject: string, agent: Agent) {
@@ -122,7 +123,7 @@ export const nameRegex = '^[a-z0-9_-]+';

export async function serverSupportsRegister(store: Store) {
const url = new URL('/register', store.getServerUrl());
const resource = await store.getResourceAsync(url.toString());
const resource = await store.getResource(url.toString());

if (!resource) {
return false;
@@ -135,6 +136,23 @@ export async function serverSupportsRegister(store: Store) {
return true;
}

/** Run this after making a call to an endpoint. Throws if something went wrong. */
function checkResourceSuccess(resource?: Resource) {
if (!resource) {
throw new Error('No resource received');
}

if (resource.error) {
throw resource.error;
}

const respName = resource.get(core.properties.name) as string;

if (!respName.includes('Success')) {
throw new Error('Expected a `success` message, did not receive one');
}
}

/** Asks the server to create an Agent + a Drive.
* Sends the confirmation email to the user.
* Throws if the name is not available or the email is invalid.
@@ -148,20 +166,7 @@ export async function register(
url.searchParams.set('name', name);
url.searchParams.set('email', email);
const resource = await store.getResourceAsync(url.toString());

if (!resource) {
throw new Error('No resource received');
}

if (resource.error) {
throw resource.error;
}

const description = resource.get(core.properties.description) as string;

if (!description.includes('success')) {
throw new Error('Expected a `success` message, did not receive one');
}
checkResourceSuccess(resource);

return;
}
@@ -175,20 +180,7 @@ export async function addPublicKey(store: Store, email: string): Promise<void> {
const url = new URL('/add-public-key', store.getServerUrl());
url.searchParams.set('email', email);
const resource = await store.getResourceAsync(url.toString());

if (!resource) {
throw new Error('No resource received');
}

if (resource.error) {
throw resource.error;
}

const description = resource.get(core.properties.description) as string;

if (!description.includes('success')) {
throw new Error('Expected a `success` message, did not receive one');
}
checkResourceSuccess(resource);

return;
}
@@ -231,7 +223,7 @@ export async function confirmEmail(
}

url.searchParams.set('public-key', await agent.getPublicKey());
const resource = await store.getResourceAsync(url.toString());
const resource = await store.getResource(url.toString());

if (!resource) {
throw new Error('no resource!');
@@ -254,7 +246,7 @@ export async function confirmEmail(
return { agent, destination };
}

function parseJwt(token) {
function parseJwt(token: string) {
try {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
14 changes: 7 additions & 7 deletions browser/react/src/useServerSupports.ts
Original file line number Diff line number Diff line change
@@ -5,16 +5,16 @@ export function useServerSupports(): ServerSupports {
const store = useStore();
const serverURL = useServerURL();
const [supports, setSupports] = useState<ServerSupports>({
emailRegister: false,
emailRegister: true,
});

useEffect(() => {
async function check() {
const res = await store.getServerSupports();
setSupports(res);
}

check();
console.log('useEffect');
// async function check() {
// const res = await store.getServerSupports();
// setSupports(res);
// }
// check();
}, [store, serverURL]);

return supports;
10 changes: 5 additions & 5 deletions cli/src/commit.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ pub fn set(context: &Context, subject: &str, property: &str, value: &str) -> Ato
Ok(r) => r,
Err(_) => atomic_lib::Resource::new(subject.into()),
};
resource.set_shortname(&property, &value, &context.store)?;
resource.set_shortname(property, value, &context.store)?;
resource.save(&context.store)?;
Ok(())
}
@@ -17,27 +17,27 @@ pub fn set(context: &Context, subject: &str, property: &str, value: &str) -> Ato
#[cfg(feature = "native")]
pub fn edit(context: &Context, subject: &str, prop: &str) -> AtomicResult<()> {
// If the resource is not found, create it
let mut resource = match context.store.get_resource(&subject) {
let mut resource = match context.store.get_resource(subject) {
Ok(r) => r,
Err(_) => atomic_lib::Resource::new(subject.into()),
};
// If the prop is not found, create it
let current_val = match resource.get_shortname(&prop, &context.store) {
let current_val = match resource.get_shortname(prop, &context.store) {
Ok(val) => val.to_string(),
Err(_) => "".to_string(),
};
let edited = edit::edit(current_val)?;
// Remove newline - or else I can's save shortnames or numbers using vim;
let trimmed = edited.trim_end_matches('\n');
resource.set_shortname(&prop, trimmed, &context.store)?;
resource.set_shortname(prop, trimmed, &context.store)?;
resource.save(&context.store)?;
Ok(())
}

/// Apply a Commit using the Remove method - removes a property from a resource
pub fn remove(context: &Context, subject: &str, prop: &str) -> AtomicResult<()> {
let mut resource = context.store.get_resource(subject)?;
resource.remove_propval_shortname(&prop, &context.store)?;
resource.remove_propval_shortname(prop, &context.store)?;
resource.save(&context.store)?;
Ok(())
}
7 changes: 3 additions & 4 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use atomic_lib::serialize::Format;
use atomic_lib::atomic_url::Routes;
use atomic_lib::{agents::generate_public_key, mapping::Mapping};
use atomic_lib::{agents::Agent, config::Config};
use atomic_lib::{errors::AtomicResult, Storelike};
@@ -114,9 +113,9 @@ pub enum SerializeOptions {
NTriples,
}

impl Into<Format> for SerializeOptions {
fn into(self) -> Format {
match self {
impl From<&SerializeOptions> for Format {
fn from(val: &SerializeOptions) -> Self {
match val {
SerializeOptions::Pretty => Format::Pretty,
SerializeOptions::Json => Format::Json,
SerializeOptions::NTriples => Format::NTriples,
2 changes: 1 addition & 1 deletion cli/src/path.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ use atomic_lib::{agents::ForAgent, errors::AtomicResult, serialize, storelike, A
/// Resolves an Atomic Path query
pub fn get_path(
context: &mut Context,
path_vec: &Vec<String>,
path_vec: &[String],
serialize: &SerializeOptions,
) -> AtomicResult<()> {
// let subcommand_matches = context.matches.subcommand_matches("get").unwrap();
4 changes: 2 additions & 2 deletions cli/src/print.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ use colored::*;

use crate::{Context, SerializeOptions};

/// Prints a resource for the terminal with readble formatting and colors
/// Prints a resource for the terminal with readable formatting and colors
pub fn pretty_print_resource(resource: &Resource, store: &impl Storelike) -> AtomicResult<String> {
let mut output = String::new();
output.push_str(&format!(
@@ -32,7 +32,7 @@ pub fn print_resource(
resource: &Resource,
serialize: &SerializeOptions,
) -> AtomicResult<()> {
let format: Format = serialize.clone().into();
let format: Format = serialize.into();
let out = match format {
Format::Json => resource.to_json(&context.store)?,
Format::JsonLd => resource.to_json_ld(&context.store)?,
4 changes: 2 additions & 2 deletions docs/src/react/useStore.md
Original file line number Diff line number Diff line change
@@ -23,10 +23,10 @@ export const Login = () => {

return (
<label>
Agent Secret
Secret
<input
type="password"
placeholder="My agent secret"
placeholder="My Secret"
value={agentSecret}
onChange={e => setAgentSecret(e.target.value)}
/>
3 changes: 3 additions & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -57,3 +57,6 @@ config = ["directories", "toml"]
html = ["kuchikiki", "lol_html", "html2md"]
db = ["sled", "bincode", "mail-send", "tokio", "async-mutex", "jwt-simple"]
rdf = ["rio_api", "rio_turtle"]

[profile.dev]
incremental = true
4 changes: 2 additions & 2 deletions lib/src/collections.rs
Original file line number Diff line number Diff line change
@@ -494,7 +494,7 @@ mod test {

#[test]
fn create_collection_nested_members_and_sorting() {
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();
let collection_builder = CollectionBuilder {
subject: "test_subject".into(),
@@ -560,7 +560,7 @@ mod test {
#[ignore]
// TODO: This currently only tests atomicdata.dev, should test local resources. These need to be rewritten
fn get_collection_params() {
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();

let collection_page_size = store
8 changes: 4 additions & 4 deletions lib/src/commit.rs
Original file line number Diff line number Diff line change
@@ -688,7 +688,7 @@ mod test {

#[test]
fn agent_and_commit() {
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();
let agent = store.create_agent(Some("test_actor")).unwrap();
let subject = "https://localhost/new_thing";
@@ -720,7 +720,7 @@ mod test {

#[test]
fn serialize_commit() {
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();
let mut set: HashMap<String, Value> = HashMap::new();
let shortname = Value::new("shortname", &DataType::String).unwrap();
@@ -749,7 +749,7 @@ mod test {
#[test]
fn signature_matches() {
let private_key = "CapMWIhFUT+w7ANv9oCPqrHrwZpkP2JhzF9JnyT6WcI=";
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();
let agent = Agent::new_from_private_key(None, &store, private_key).unwrap();
assert_eq!(
@@ -786,7 +786,7 @@ mod test {
#[test]

fn invalid_subjects() {
let mut store = crate::Store::init().unwrap();
let store = crate::Store::init().unwrap();
store.populate().unwrap();
let agent = store.create_agent(Some("test_actor")).unwrap();
let resource = Resource::new("https://localhost/test_resource".into());
7 changes: 3 additions & 4 deletions lib/src/db.rs
Original file line number Diff line number Diff line change
@@ -133,7 +133,7 @@ impl Db {
pub fn init_temp(id: &str) -> AtomicResult<Db> {
let tmp_dir_path = format!(".temp/db/{}", id);
let _try_remove_existing = std::fs::remove_dir_all(&tmp_dir_path);
let mut store = Db::init(std::path::Path::new(&tmp_dir_path), "https://localhost")?;
let store = Db::init(std::path::Path::new(&tmp_dir_path), "https://localhost")?;
let agent = store.create_agent(None)?;
store.set_default_agent(agent);
store.populate()?;
@@ -953,9 +953,8 @@ impl Storelike for Db {
)
}

fn populate(&mut self) -> AtomicResult<()> {
crate::populate::populate_all(self)?;
Ok(())
fn populate(&self) -> AtomicResult<()> {
crate::populate::populate_all(self)
}

#[instrument(skip(self))]
2 changes: 1 addition & 1 deletion lib/src/db/test.rs
Original file line number Diff line number Diff line change
@@ -328,7 +328,7 @@ fn queries() {
r.set(sort_by.into(), Value::Markdown("!first".into()), store)
.unwrap();
let resp = r.save(store).unwrap();
resource_changed_order_opt = resp.resource_new.clone();
resource_changed_order_opt = resp.resource_new;
}
prev_resource = r.clone();
}
21 changes: 10 additions & 11 deletions lib/src/plugins/add_pubkey.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ pub fn confirm_add_pubkey() -> Endpoint {
Endpoint {
path: urls::PATH_CONFIRM_PUBKEY.to_string(),
params: [urls::TOKEN.to_string(), urls::INVITE_PUBKEY.to_string()].into(),
description: "Confirms a token to add a new Public Key.".to_string(),
description: "Confirms a token to add a new PublicKey.".to_string(),
shortname: "request-pubkey-reset".to_string(),
handle: Some(handle_confirm_add_pubkey),
handle_post: None,
@@ -58,12 +58,12 @@ pub fn handle_request_email_pubkey(context: HandleGetContext) -> AtomicResult<Re
return request_email_add_pubkey().to_resource(store);
};

// Find the agent by their email
// If we can't find the agent by email, we should still return a `success` response,
// in order to prevent users to know that the email exists.
let msg = "Email sent (if available)!";
let agent = match Agent::from_email(&email.to_string(), store) {
Ok(a) => a,
// If we can't find the agent, we should still return a `success` response,
// in order to prevent users to know that the email exists.
Err(_) => return return_success(),
Err(_) => return return_success(msg),
};

// send the user an e-mail to confirm sign up
@@ -80,11 +80,10 @@ pub fn handle_request_email_pubkey(context: HandleGetContext) -> AtomicResult<Re
confirm_url.set_query(Some(&format!("token={}", token)));
let message = MailMessage {
to: email,
subject: "Add a new Passphrase to your account".to_string(),
body: "You've requested adding a new Passphrase. Click the link below to do so!"
.to_string(),
subject: "Add a new Secret to your account".to_string(),
body: "You've requested adding a new Secret. Click the link below to do so!".to_string(),
action: Some(MailAction {
name: "Add new Passphrase to account".to_string(),
name: "Add new Secret to account".to_string(),
url: confirm_url.into(),
}),
};
@@ -96,7 +95,7 @@ pub fn handle_request_email_pubkey(context: HandleGetContext) -> AtomicResult<Re
.unwrap_or_else(|e| tracing::error!("Error sending email: {}", e));
});

return_success()
return_success(msg)
}

pub fn handle_confirm_add_pubkey(context: HandleGetContext) -> AtomicResult<Resource> {
@@ -131,5 +130,5 @@ pub fn handle_confirm_add_pubkey(context: HandleGetContext) -> AtomicResult<Reso
agent.push(urls::ACTIVE_KEYS, pubkey.into(), true)?;
agent.save(store)?;

return_success()
return_success("")
}
2 changes: 1 addition & 1 deletion lib/src/plugins/register.rs
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ pub fn handle_register_name_and_email(context: HandleGetContext) -> AtomicResult
.unwrap_or_else(|e| tracing::error!("Error sending email: {}", e));
});

return_success()
return_success("Account generated")
}

#[tracing::instrument()]
5 changes: 3 additions & 2 deletions lib/src/plugins/utils.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,9 @@
use crate::{errors::AtomicResult, urls, Resource, Value};

/// Returns a Resource with a description of "success"
pub fn return_success() -> AtomicResult<Resource> {
pub fn return_success(message: &str) -> AtomicResult<Resource> {
let mut resource = Resource::new("unknown".into());
resource.set_unsafe(urls::DESCRIPTION.into(), Value::String("success".into()));
resource.set_unsafe(urls::DESCRIPTION.into(), Value::String(message.into()));
resource.set_unsafe(urls::NAME.into(), Value::String("Success".into()));
Ok(resource)
}
3 changes: 1 addition & 2 deletions lib/src/populate.rs
Original file line number Diff line number Diff line change
@@ -360,7 +360,7 @@ pub fn populate_sidebar_items(store: &crate::Db) -> AtomicResult<()> {

/// Runs all populate commands. Optionally runs index (blocking), which can be slow!
#[cfg(feature = "db")]
pub fn populate_all(store: &mut crate::Db) -> AtomicResult<()> {
pub fn populate_all(store: &crate::Db) -> AtomicResult<()> {
// populate_base_models should be run in init, instead of here, since it will result in infinite loops without
populate_default_store(store)
.map_err(|e| format!("Failed to populate default store. {}", e))?;
@@ -372,6 +372,5 @@ pub fn populate_all(store: &mut crate::Db) -> AtomicResult<()> {
populate_collections(store).map_err(|e| format!("Failed to populate collections. {}", e))?;
populate_sidebar_items(store)
.map_err(|e| format!("Failed to populate sidebar items. {}", e))?;
store.register_default_endpoints()?;
Ok(())
}
2 changes: 1 addition & 1 deletion lib/src/storelike.rs
Original file line number Diff line number Diff line change
@@ -387,7 +387,7 @@ pub trait Storelike: Sized {
}

/// Loads the default store. For DBs it also adds default Collections and Endpoints.
fn populate(&mut self) -> AtomicResult<()> {
fn populate(&self) -> AtomicResult<()> {
crate::populate::populate_base_models(self)?;
crate::populate::populate_default_store(self)
}
2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ name = "atomic-server"
path = "src/bin.rs"

[build-dependencies]
dircpy = "0.3.15"
dircpy = "0.3.19"
static-files = "0.2"
walkdir = "2"

13 changes: 4 additions & 9 deletions server/build.rs
Original file line number Diff line number Diff line change
@@ -21,17 +21,12 @@ fn main() -> std::io::Result<()> {
// Uncomment this line if you want faster builds during development
// return Ok(());
const BROWSER_ROOT: &str = "../browser/";
let dirs: Dirs = {
Dirs {
js_dist_source: PathBuf::from("../browser/data-browser/dist"),
js_dist_tmp: PathBuf::from("./assets_tmp"),
src_browser: PathBuf::from("../browser/data-browser/src"),
browser_root: PathBuf::from(BROWSER_ROOT),
}
};
println!("cargo:rerun-if-changed={}", BROWSER_ROOT);
// Check if we're likely running in a check-like context
let opt_level = std::env::var("OPT_LEVEL").unwrap_or_else(|_| "0".to_string());
let profile = std::env::var("PROFILE").unwrap_or_else(|_| "release".to_string());

let is_check_like = profile == "debug" && opt_level == "0";
let is_check_like = false; // profile == "debug" && opt_level == "0";

if is_check_like {
println!("cargo:rerun-if-changed=build.rs");
22 changes: 17 additions & 5 deletions server/src/appstate.rs
Original file line number Diff line number Diff line change
@@ -52,17 +52,29 @@ impl AppState {
tracing::warn!("Development mode is enabled. This will use staging environments for services like LetsEncrypt.");
}

let mut store = atomic_lib::Db::init(&config.store_path, &config.server_url.clone())?;
let mut store = init_store(&config)?;

let no_server_resource = store.get_resource(&config.server_url).is_err();
if no_server_resource {
tracing::warn!("Server URL resource not found. This is likely because the server URL has changed. Initializing a new database...");
}
let should_init = !&config.store_path.exists() || config.initialize || no_server_resource;
if should_init {
let should_initialize =
!&config.store_path.exists() || config.initialize || no_server_resource;
if should_initialize {
tracing::info!("Initialize: creating and populating new Database...");
atomic_lib::populate::populate_default_store(&store)
.map_err(|e| format!("Failed to populate default store. {}", e))?;
}
if let Some(host) = &config.opts.smpt_host {
store
.set_smtp_config(SmtpConfig {
host: host.clone(),
port: config.opts.smpt_port,
})
.await?;
} else {
tracing::info!("No SMTP_HOST found, not starting email server.")
}

// Initialize search constructs
let search_state = SearchState::new(&config)
@@ -93,7 +105,7 @@ impl AppState {

// If the user changes their server_url, the drive will not exist.
// In this situation, we should re-build a new drive from scratch.
if should_init {
if should_initialize {
atomic_lib::populate::populate_all(&store)?;
// Building the index here is needed to perform Queries on imported resources
let store_clone = store.clone();
@@ -191,8 +203,8 @@ fn set_default_agent(config: &Config, store: &impl Storelike) -> AtomicServerRes
created_at: 0,
name: None,
};
store.set_default_agent(agent);
tracing::info!("Default Agent is set: {}", &agent.subject);
store.set_default_agent(agent);
Ok(())
}

5 changes: 3 additions & 2 deletions server/src/bin.rs
Original file line number Diff line number Diff line change
@@ -68,7 +68,8 @@ async fn main_wrapped() -> errors::AtomicServerResult<()> {
let importer_subject = if let Some(i) = &import_opts.parent {
i.into()
} else {
store
appstate
.store
.get_self_url()
.expect("No self URL")
.set_route(Routes::Import)
@@ -83,7 +84,7 @@ async fn main_wrapped() -> errors::AtomicServerResult<()> {
} else {
atomic_lib::parse::SaveOpts::Commit
},
signer: Some(store.get_default_agent()?),
signer: Some(appstate.store.get_default_agent()?),
};
println!("Importing...");
appstate.store.import(&readstring, &parse_opts)?;
1 change: 0 additions & 1 deletion server/src/handlers/commit.rs
Original file line number Diff line number Diff line change
@@ -30,7 +30,6 @@ pub async fn post_commit(
// https://github.com/atomicdata-dev/atomic-server/issues/412
validate_previous_commit: false,
validate_for_agent: Some(incoming_commit.signer.to_string()),
validate_subject_url_parent: true,
update_index: true,
};
let commit_response = store.apply_commit(incoming_commit, &opts)?;
3 changes: 1 addition & 2 deletions server/src/handlers/export.rs
Original file line number Diff line number Diff line change
@@ -5,9 +5,8 @@ use actix_web::http::header::{ContentDisposition, DispositionParam, DispositionT
use actix_web::{web, HttpResponse};
use atomic_lib::agents::ForAgent;
use atomic_lib::errors::AtomicResult;
use atomic_lib::storelike::Query;
use atomic_lib::values::SubResource;
use atomic_lib::{urls, Db, Resource, Storelike, Value};
use atomic_lib::{urls, Db, Query, Resource, Storelike, Value};
use chrono::DateTime;
use serde::Deserialize;

6 changes: 3 additions & 3 deletions server/src/handlers/search.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ use simple_server_timing_header::Timer;
use tantivy::{
collector::TopDocs,
query::{BooleanQuery, BoostQuery, Occur, Query, QueryParser, TermQuery},
schema::IndexRecordOption,
schema::{IndexRecordOption, OwnedValue},
tokenizer::{TokenStream, Tokenizer},
Term,
};
@@ -263,12 +263,12 @@ fn build_parent_query(subject: &str, fields: &Fields, store: &Db) -> AtomicServe
}

fn unpack_value(
value: &tantivy::schema::OwnedValue,
value: &OwnedValue,
document: &tantivy::TantivyDocument,
name: String,
) -> Result<String, AtomicServerError> {
match value {
tantivy::schema::OwnedValue::Str(s) => Ok(s.to_string()),
OwnedValue::Str(s) => Ok(s.to_string()),
_else => Err(format!(
"Search schema error: {} is not a string! Doc: {:?}",
name, document
2 changes: 1 addition & 1 deletion server/src/https.rs
Original file line number Diff line number Diff line change
@@ -287,7 +287,7 @@ pub async fn request_cert(config: &crate::config::Config) -> AtomicServerResult<
// Exponentially back off until the order becomes ready or invalid.
let mut tries = 1u8;
let mut delay = std::time::Duration::from_millis(250);
let url = authorizations.get(0).expect("Authorizations is empty");
let url = authorizations.first().expect("Authorizations is empty");
let state = loop {
let state = order.state();
info!("Order state: {:#?}", state);