Skip to content

Commit

Permalink
Handle illegal characters in labels on the references form
Browse files Browse the repository at this point in the history
  • Loading branch information
nygrenh committed Dec 18, 2024
1 parent 4566b7f commit dba2be5
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 27 deletions.
59 changes: 36 additions & 23 deletions services/main-frontend/src/components/forms/EditReferenceForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { css } from "@emotion/css"
import styled from "@emotion/styled"
import React, { useState } from "react"
import React from "react"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"

import {
areCitationsValid,
safeParseReferences,
useCitataionLabelsThatWillChange,
} from "./NewReferenceForm"

import { MaterialReference, NewMaterialReference } from "@/shared-module/common/bindings"
import Button from "@/shared-module/common/components/Button"
import TextAreaField from "@/shared-module/common/components/InputFields/TextAreaField"
Expand All @@ -25,7 +31,6 @@ interface EditReferenceFields {
reference: string
}

const EMPTY_STRING = ""
const ErrorText = styled.p`
color: red;
`
Expand All @@ -42,34 +47,31 @@ const EditReferenceForm: React.FC<React.PropsWithChildren<EditReferenceFormProps
register,
handleSubmit,
formState: { errors },
} = useForm<EditReferenceFields>()
watch,
} = useForm<EditReferenceFields>({ defaultValues: { reference: reference.reference } })

const watchedReference = watch("reference")

const [errorMessage, setErrorMessage] = useState("")
const citationLabelsThatWillChange = useCitataionLabelsThatWillChange(watchedReference)

const isValidReference = React.useMemo(() => {
return areCitationsValid(watchedReference)
}, [watchedReference])

const onEditReferenceWrapper = handleSubmit((data) => {
try {
const cite = new Cite(data.reference)
const editedReference = cite.data[0]
const cite = safeParseReferences(data.reference)
const referenceData = cite.data[0]
const editedReference = new Cite(referenceData)
onEdit(courseId, reference.id, {
reference: data.reference,
citation_key: editedReference.id,
reference: editedReference.get({ type: "string", style: "bibtex", lang: "en-US" }),
citation_key: referenceData.id,
})
} catch (error: unknown) {
setErrorMessage(t("reference-parsing-error"))
setTimeout(() => {
setErrorMessage(EMPTY_STRING)
}, 5000)
console.error(error)
}
})

let defaultValueReference: string = reference.reference
try {
const cite = new Cite(reference.reference)
defaultValueReference = cite.get({ type: "string", style: "bibtex", lang: "en-US" })
} catch (error: unknown) {
console.warn(error)
}

return (
<form
onSubmit={onEditReferenceWrapper}
Expand All @@ -83,15 +85,20 @@ const EditReferenceForm: React.FC<React.PropsWithChildren<EditReferenceFormProps
error={errors["reference"]}
placeholder={REFERENCE}
{...register("reference", { required: true })}
defaultValue={defaultValueReference}
rows={5}
className={css`
width: 100%;
margin-bottom: 0.5rem;
`}
autoResize
/>
<br />
{errorMessage && <ErrorText> {errorMessage} </ErrorText>}
{!isValidReference && <ErrorText> {t("reference-parsing-error")} </ErrorText>}
{citationLabelsThatWillChange.map((c) => (
<ErrorText key={c.original}>
{t("reference-parsing-error-label-change", { original: c.original, safe: c.safe })}
</ErrorText>
))}
<Button variant="primary" size="medium" type="submit">
{t("save")}
</Button>
Expand All @@ -103,7 +110,13 @@ const EditReferenceForm: React.FC<React.PropsWithChildren<EditReferenceFormProps
>
{t("delete")}
</Button>
<Button variant="secondary" size="medium" type="button" onClick={onCancel}>
<Button
variant="secondary"
size="medium"
type="button"
onClick={onCancel}
disabled={!isValidReference}
>
{t("close")}
</Button>
</form>
Expand Down
51 changes: 47 additions & 4 deletions services/main-frontend/src/components/forms/NewReferenceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,22 @@ const NewReferenceForm: React.FC<React.PropsWithChildren<NewReferenceFormProps>>
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<NewReferenceFields>()

const references = watch("references")

const [errorMessage, setErrorMessage] = useState("")
const onCreateNewReferenceWrapper = handleSubmit((data) => {
try {
const cite = new Cite(data.references)
const references = cite.data.map((c: { id: string }) => {
const rawCite = new Cite(data.references)
const cite = new Cite(rawCite.get({ type: "string", style: "bibtex", lang: "en-US" }))
const references = cite.data.map((c: { id: string; "citation-key": string }) => {
const ci = new Cite(c)

return {
citation_key: c.id,
citation_key: c["citation-key"],
reference: ci.get({ type: "string", style: "bibtex", lang: "en-US" }),
}
})
Expand All @@ -57,6 +62,8 @@ const NewReferenceForm: React.FC<React.PropsWithChildren<NewReferenceFormProps>>
}
})

const citationLabelsThatWillChange = useCitataionLabelsThatWillChange(references)

return (
<form
onSubmit={onCreateNewReferenceWrapper}
Expand All @@ -74,10 +81,15 @@ const NewReferenceForm: React.FC<React.PropsWithChildren<NewReferenceFormProps>>
className={css`
width: 100%;
margin-bottom: 0.5rem;
height: 150px;
`}
autoResize
/>
{errorMessage && <ErrorText> {errorMessage} </ErrorText>}
{citationLabelsThatWillChange.map((c) => (
<ErrorText key={c.original}>
{t("reference-parsing-error-label-change", { original: c.original, safe: c.safe })}
</ErrorText>
))}
<br />
<Button variant="primary" size="medium" type="submit" value={t("button-text-submit")}>
{t("button-text-submit")}
Expand All @@ -88,5 +100,36 @@ const NewReferenceForm: React.FC<React.PropsWithChildren<NewReferenceFormProps>>
</form>
)
}
/// Have to construct the citation twice because the library changes the label if it contains any non-safe characters, and we want to persist the safe version of the label
export function safeParseReferences(references: string): typeof Cite {
const rawCite = new Cite(references)
const cite = new Cite(rawCite.get({ type: "string", style: "bibtex", lang: "en-US" }))
return cite
}

/// Can be used to detect if citation.js will change the citation key to a safe version
export function useCitataionLabelsThatWillChange(
references: string,
): { original: string; safe: string }[] {
const safeCite = safeParseReferences(references)
const unsafeCite = new Cite(references)
const keys = safeCite.data
.map((c: { "citation-key": string }, i: number) => ({
original: unsafeCite.data[i]["citation-key"],
safe: c["citation-key"],
}))
.filter((c: { original: string; safe: string }) => c.original !== c.safe)
return keys
}

export function areCitationsValid(references: string): boolean {
try {
const cite = new Cite(references)
cite.get({ type: "string", style: "bibtex", lang: "en-US" })
return true
} catch (error: unknown) {
return false
}
}

export default NewReferenceForm
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@
"reference-added-succesfully": "تمت إضافة المرجع بنجاح",
"reference-deleted-succesfully": "تم حذف المرجع بنجاح",
"reference-parsing-error": "خطأ: هذا التنسيق غير مدعوم أو غير معترف به",
"reference-parsing-error-label-change": "سيتم تغيير التسمية {{original}} إلى {{safe}} لأنها تحتوي على أحرف غير آمنة.",
"reference-updated-succesfully": "تم تحديث المرجع بنجاح",
"references": "المراجع",
"register-completion": "تسجيل الإكمال",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@
"reference-added-succesfully": "Reference added succesfully",
"reference-deleted-succesfully": "Reference deleted succesfully",
"reference-parsing-error": "Error: This format is not supported or recognized",
"reference-parsing-error-label-change": "The label {{original}} will be changed {{safe}} because it contains unsafe characters.",
"reference-updated-succesfully": "Reference updated succesfully",
"references": "References",
"register-completion": "Register completion",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@
"reference-added-succesfully": "Lähdeviite lisätty",
"reference-deleted-succesfully": "Lähdeviite poistettu",
"reference-parsing-error": "Virhe: Tätä muotoa ei tueta tai tunnisteta",
"reference-parsing-error-label-change": "Tunniste {{original}} muutetaan {{safe}}, koska se sisältää turvattomia merkkejä.",
"reference-updated-succesfully": "Lähdeviite päivitetty",
"references": "Lähteet",
"register-completion": "Suorituksen kirjaaminen",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@
"reference-added-succesfully": "Посилання успішно додано",
"reference-deleted-succesfully": "Посилання успішно видалено",
"reference-parsing-error": "Помилка: цей формат не підтримується або не розпізнається",
"reference-parsing-error-label-change": "Мітка {{original}} буде змінена на {{safe}}, оскільки вона містить небезпечні символи.",
"reference-updated-succesfully": "Посилання успішно оновлено",
"references": "Посилання",
"register-completion": "Завершення реєстрації",
Expand Down

0 comments on commit dba2be5

Please sign in to comment.