mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Zotero: fix for 6.3.0
This commit is contained in:
@@ -140,6 +140,7 @@ const rawLinkedFileData = z.discriminatedUnion('provider', [
|
|||||||
format: z.enum(['bibtex', 'biblatex']).optional(),
|
format: z.enum(['bibtex', 'biblatex']).optional(),
|
||||||
group_id: zz.routeSegment().nullish(),
|
group_id: zz.routeSegment().nullish(),
|
||||||
importer_id: z.string().optional(),
|
importer_id: z.string().optional(),
|
||||||
|
importer_name: z.string().optional(),
|
||||||
v1_importer_id: z.number().optional(),
|
v1_importer_id: z.number().optional(),
|
||||||
importedAt: z.iso.datetime().optional(),
|
importedAt: z.iso.datetime().optional(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ export type LinkedFileData = {
|
|||||||
}
|
}
|
||||||
zotero: {
|
zotero: {
|
||||||
provider: 'zotero'
|
provider: 'zotero'
|
||||||
zoteroGroupId?: string
|
group_id: string | null
|
||||||
|
format: 'bibtex' | 'biblatex'
|
||||||
importedAt: Date | string
|
importedAt: Date | string
|
||||||
importedByUserId: string
|
importer_id: string
|
||||||
importedByName: string
|
importer_name: string
|
||||||
bibFormat: 'bibtex' | 'biblatex'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ import ZoteroApiClient from './ZoteroApiClient.mjs'
|
|||||||
* linkedFileData shape:
|
* linkedFileData shape:
|
||||||
* {
|
* {
|
||||||
* provider: 'zotero'
|
* provider: 'zotero'
|
||||||
* zoteroGroupId?: string
|
* group_id: string | null
|
||||||
* importedAt: Date | string
|
* importedAt: Date | string
|
||||||
* importedByUserId: string
|
* importer_id: string
|
||||||
* importedByName: string
|
* importer_name: string
|
||||||
* bibFormat: 'bibtex' || 'biblatex'
|
* format: 'bibtex' || 'biblatex'
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* - If zoteroGroupId is present, export that group's library.
|
* - If group_id is present, export that group's library.
|
||||||
* - Otherwise, export the user's personal library ("My Library").
|
* - Otherwise, export the user's personal library ("My Library").
|
||||||
*/
|
*/
|
||||||
async function createLinkedFile(
|
async function createLinkedFile(
|
||||||
@@ -37,8 +37,8 @@ async function createLinkedFile(
|
|||||||
userId
|
userId
|
||||||
) {
|
) {
|
||||||
|
|
||||||
linkedFileData.importedByUserId = userId
|
linkedFileData.importer_id = userId
|
||||||
linkedFileData.importedByName = await _getUserName(userId) || 'Unknown'
|
linkedFileData.importer_name = await _getUserName(userId) || 'Unknown'
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
{ projectId, userId, linkedFileData },
|
{ projectId, userId, linkedFileData },
|
||||||
@@ -76,16 +76,16 @@ async function refreshLinkedFile(
|
|||||||
// refresh importer's displayed name
|
// refresh importer's displayed name
|
||||||
// if the importer is the owner, name is not displayed, refresh is not needed
|
// if the importer is the owner, name is not displayed, refresh is not needed
|
||||||
// if the importer is not available, the old name is preserved
|
// if the importer is not available, the old name is preserved
|
||||||
const userName = await _getUserName(linkedFileData.importedByUserId)
|
const userName = await _getUserName(linkedFileData.importer_id)
|
||||||
if (userName && linkedFileData.importedByUserId != userId) {
|
if (userName && linkedFileData.importer_id != userId) {
|
||||||
linkedFileData.importedByName = userName
|
linkedFileData.importer_name = userName
|
||||||
const { element, path } = await ProjectLocator.promises.findElement({
|
const { element, path } = await ProjectLocator.promises.findElement({
|
||||||
project_id: projectId,
|
project_id: projectId,
|
||||||
element_id: parentFolderId,
|
element_id: parentFolderId,
|
||||||
type: 'folders'
|
type: 'folders'
|
||||||
})
|
})
|
||||||
const fileIndex = element.fileRefs.findIndex(file => file.name === name)
|
const fileIndex = element.fileRefs.findIndex(file => file.name === name)
|
||||||
const updatePath = `${path.mongo}.fileRefs.${fileIndex}.linkedFileData.importedByName`
|
const updatePath = `${path.mongo}.fileRefs.${fileIndex}.linkedFileData.importer_name`
|
||||||
await Project.updateOne({ _id: projectId }, { $set: { [updatePath]: userName } })
|
await Project.updateOne({ _id: projectId }, { $set: { [updatePath]: userName } })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,12 +103,12 @@ async function refreshLinkedFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function _getBibtex(linkedFileData) {
|
async function _getBibtex(linkedFileData) {
|
||||||
const userId = linkedFileData.importedByUserId
|
const userId = linkedFileData.importer_id
|
||||||
try {
|
try {
|
||||||
return await ZoteroApiClient.getLibraryBibtex(
|
return await ZoteroApiClient.getLibraryBibtex(
|
||||||
userId,
|
userId,
|
||||||
linkedFileData.zoteroGroupId, // == null for main library
|
linkedFileData.group_id, // == null for main library
|
||||||
linkedFileData.bibFormat || 'bibtex'
|
linkedFileData.format || 'bibtex'
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
||||||
@@ -117,11 +117,11 @@ async function _getBibtex(linkedFileData) {
|
|||||||
throw new LinkedFilesErrors.AccessDeniedError('Zotero access denied').withCause(err)
|
throw new LinkedFilesErrors.AccessDeniedError('Zotero access denied').withCause(err)
|
||||||
}
|
}
|
||||||
if (err instanceof ServiceNotConfiguredError) {
|
if (err instanceof ServiceNotConfiguredError) {
|
||||||
logger.debug({ userId: linkedFileData.importedByUserId, err }, 'Zotero account not linked')
|
logger.debug({ userId: linkedFileData.importer_id, err }, 'Zotero account not linked')
|
||||||
throw new LinkedFilesErrors.AccessDeniedError('Zotero account not linked').withCause(err)
|
throw new LinkedFilesErrors.AccessDeniedError('Zotero account not linked').withCause(err)
|
||||||
}
|
}
|
||||||
if (err instanceof NotFoundError) {
|
if (err instanceof NotFoundError) {
|
||||||
logger.debug({ group: linkedFileData.zoteroGroupId, err }, 'Zotero group is not found')
|
logger.debug({ group: linkedFileData.group_id, err }, 'Zotero group is not found')
|
||||||
throw new LinkedFilesErrors.SourceFileNotFoundError('Zotero group is not found').withCause(err)
|
throw new LinkedFilesErrors.SourceFileNotFoundError('Zotero group is not found').withCause(err)
|
||||||
}
|
}
|
||||||
logger.error({ linkedFileData, err }, 'failed to retrieve bib file from Zotero')
|
logger.error({ linkedFileData, err }, 'failed to retrieve bib file from Zotero')
|
||||||
@@ -132,15 +132,13 @@ async function _getBibtex(linkedFileData) {
|
|||||||
function _sanitizeData(data) {
|
function _sanitizeData(data) {
|
||||||
return {
|
return {
|
||||||
provider: 'zotero',
|
provider: 'zotero',
|
||||||
...(data.zoteroGroupId && {
|
group_id: data.group_id ?? null,
|
||||||
zoteroGroupId: data.zoteroGroupId,
|
|
||||||
}),
|
|
||||||
importedAt: data.importedAt,
|
importedAt: data.importedAt,
|
||||||
...(data.importedByUserId && {
|
...(data.importer_id && {
|
||||||
importedByUserId: data.importedByUserId,
|
importer_id: data.importer_id,
|
||||||
}),
|
}),
|
||||||
importedByName: data.importedByName || 'Unknown',
|
importer_name: data.importer_name || 'Unknown',
|
||||||
bibFormat: (data.bibFormat === 'biblatex') ? 'biblatex' : 'bibtex'
|
format: (data.format === 'biblatex') ? 'biblatex' : 'bibtex'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import ErrorMessage from '@/features/file-tree/components/file-tree-create/error
|
|||||||
import OLFormGroup from '@/shared/components/ol/ol-form-group'
|
import OLFormGroup from '@/shared/components/ol/ol-form-group'
|
||||||
import OLFormLabel from '@/shared/components/ol/ol-form-label'
|
import OLFormLabel from '@/shared/components/ol/ol-form-label'
|
||||||
import OLFormSelect from '@/shared/components/ol/ol-form-select'
|
import OLFormSelect from '@/shared/components/ol/ol-form-select'
|
||||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
import Notification from '@/shared/components/notification'
|
||||||
|
|
||||||
type ZoteroGroup = {
|
type ZoteroGroup = {
|
||||||
id: string
|
id: string
|
||||||
@@ -23,7 +23,7 @@ export default function FileTreeImportFromZotero({ groups }: FileTreeImportFromZ
|
|||||||
const { name, setName } = useFileTreeCreateName()
|
const { name, setName } = useFileTreeCreateName()
|
||||||
const { setValid } = useFileTreeCreateForm()
|
const { setValid } = useFileTreeCreateForm()
|
||||||
const { finishCreatingLinkedFile, error, inFlight } = useFileTreeActionable()
|
const { finishCreatingLinkedFile, error, inFlight } = useFileTreeActionable()
|
||||||
const [selectedGroupId, setSelectedGroupId] = useState<string>('')
|
const [selectedGroupId, setSelectedGroupId] = useState<string>("")
|
||||||
const [selectedFormat, setSelectedFormat] = useState<string>('bibtex')
|
const [selectedFormat, setSelectedFormat] = useState<string>('bibtex')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,7 +40,10 @@ export default function FileTreeImportFromZotero({ groups }: FileTreeImportFromZ
|
|||||||
finishCreatingLinkedFile({
|
finishCreatingLinkedFile({
|
||||||
name,
|
name,
|
||||||
provider: 'zotero',
|
provider: 'zotero',
|
||||||
data: { zoteroGroupId: selectedGroupId, bibFormat: selectedFormat }
|
data: {
|
||||||
|
group_id: selectedGroupId || undefined,
|
||||||
|
format: selectedFormat,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ export function TPRFileViewInfo({ file }: TPRFileViewInfoProps) {
|
|||||||
const formattedDate = formatTime(importedAt)
|
const formattedDate = formatTime(importedAt)
|
||||||
const relative = relativeDate(importedAt)
|
const relative = relativeDate(importedAt)
|
||||||
|
|
||||||
const importedByUserId = (file.linkedFileData as any)?.importedByUserId
|
const importer_id = (file.linkedFileData as any)?.importer_id
|
||||||
const importedByName = (file.linkedFileData as any)?.importedByName || 'Unknown'
|
const importer_name = (file.linkedFileData as any)?.importer_name || 'Unknown'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
<LinkedFileIcon />
|
<LinkedFileIcon />
|
||||||
|
|
||||||
{(importedByUserId === getMeta('ol-user_id')) ? (
|
{(importer_id === getMeta('ol-user_id')) ? (
|
||||||
t('imported_from_zotero_at_date', {
|
t('imported_from_zotero_at_date', {
|
||||||
formattedDate,
|
formattedDate,
|
||||||
relativeDate: relative,
|
relativeDate: relative,
|
||||||
@@ -41,7 +41,7 @@ export function TPRFileViewInfo({ file }: TPRFileViewInfoProps) {
|
|||||||
t('imported_from_zotero_at_date_by', {
|
t('imported_from_zotero_at_date_by', {
|
||||||
formattedDate,
|
formattedDate,
|
||||||
relativeDate: relative,
|
relativeDate: relative,
|
||||||
importedByName,
|
importer_name,
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
import Notification from '@/shared/components/notification'
|
||||||
import type { LinkedFile, LinkedFileData } from '@/features/file-view/types/binary-file'
|
import type { LinkedFile, LinkedFileData } from '@/features/file-view/types/binary-file'
|
||||||
import { hasProvider } from '@/features/file-view/types/binary-file'
|
import { hasProvider } from '@/features/file-view/types/binary-file'
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export function TPRFileViewRefreshError({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="file-view-error">
|
<div className="file-view-error">
|
||||||
<OLNotification type="error" content={message} />
|
<Notification type="error" content={message} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import useAsync from '@/shared/hooks/use-async'
|
|||||||
import { getJSON } from '@/infrastructure/fetch-json'
|
import { getJSON } from '@/infrastructure/fetch-json'
|
||||||
import { debugConsole } from '@/utils/debugging'
|
import { debugConsole } from '@/utils/debugging'
|
||||||
import OLButton from '@/shared/components/ol/ol-button'
|
import OLButton from '@/shared/components/ol/ol-button'
|
||||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
import Notification from '@/shared/components/notification'
|
||||||
import { useFileTreeActionable } from '@/features/file-tree/contexts/file-tree-actionable'
|
import { useFileTreeActionable } from '@/features/file-tree/contexts/file-tree-actionable'
|
||||||
import FileTreeModalCreateFileMode from '@/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode'
|
import FileTreeModalCreateFileMode from '@/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode'
|
||||||
import FileTreeCreateNameProvider from '@/features/file-tree/contexts/file-tree-create-name'
|
import FileTreeCreateNameProvider from '@/features/file-tree/contexts/file-tree-create-name'
|
||||||
@@ -108,7 +108,7 @@ export function CreateFilePane() {
|
|||||||
}
|
}
|
||||||
} else if (isGroupsError) {
|
} else if (isGroupsError) {
|
||||||
return (
|
return (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="error"
|
type="error"
|
||||||
content={t('zotero_groups_loading_error', {
|
content={t('zotero_groups_loading_error', {
|
||||||
provider: t('zotero'),
|
provider: t('zotero'),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
OLModalFooter,
|
OLModalFooter,
|
||||||
} from '@/shared/components/ol/ol-modal'
|
} from '@/shared/components/ol/ol-modal'
|
||||||
import OLButton from '@/shared/components/ol/ol-button'
|
import OLButton from '@/shared/components/ol/ol-button'
|
||||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
import Notification from '@/shared/components/notification'
|
||||||
|
|
||||||
import { ProjectSyncState, GitSyncModalStatus } from '../../types/git-sync-types'
|
import { ProjectSyncState, GitSyncModalStatus } from '../../types/git-sync-types'
|
||||||
|
|
||||||
@@ -51,19 +51,19 @@ const ZoteroLinkInfoModal = ({ show, isError, handleHide }: ZoteroLinkInfoModalP
|
|||||||
|
|
||||||
<OLModalBody>
|
<OLModalBody>
|
||||||
{showUnlinkInfo ? (
|
{showUnlinkInfo ? (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="warning"
|
type="warning"
|
||||||
content={t('unlink_warning_reference', { provider: t('zotero') })}
|
content={t('unlink_warning_reference', { provider: t('zotero') })}
|
||||||
/>
|
/>
|
||||||
) : isError ? (
|
) : isError ? (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="error"
|
type="error"
|
||||||
content={t('problem_checking_connection_with_provider', {
|
content={t('problem_checking_connection_with_provider', {
|
||||||
provider: t('zotero'),
|
provider: t('zotero'),
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="info"
|
type="info"
|
||||||
content={
|
content={
|
||||||
<Trans
|
<Trans
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
OLModalHeader,
|
OLModalHeader,
|
||||||
OLModalTitle,
|
OLModalTitle,
|
||||||
} from '@/shared/components/ol/ol-modal'
|
} from '@/shared/components/ol/ol-modal'
|
||||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
import Notification from '@/shared/components/notification'
|
||||||
import ZoteroLogo from '@/shared/svgs/zotero-logo'
|
import ZoteroLogo from '@/shared/svgs/zotero-logo'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,14 +97,14 @@ export const ZoteroWidget = function ZoteroWidget() {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
{isErrorConnCheck && (
|
{isErrorConnCheck && (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="error"
|
type="error"
|
||||||
content={t('problem_checking_connection_with_provider', { provider: t('zotero') })}
|
content={t('problem_checking_connection_with_provider', { provider: t('zotero') })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isErrorUnlink && (
|
{isErrorUnlink && (
|
||||||
<OLNotification
|
<Notification
|
||||||
type="error"
|
type="error"
|
||||||
content={t('generic_something_went_wrong')}
|
content={t('generic_something_went_wrong')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user