このコミットが含まれているのは:
@@ -0,0 +1,196 @@
|
||||
import type { PostImportResultRow,
|
||||
PostImportRow } from '@/lib/postImportTypes'
|
||||
|
||||
const hasSkipReason = (row: PostImportRow): boolean =>
|
||||
row.skipReason === 'existing'
|
||||
|
||||
const hasValidationErrors = (row: PostImportRow): boolean =>
|
||||
Object.keys (row.validationErrors ?? { }).length > 0
|
||||
|
||||
const rowChanged = (
|
||||
previous: PostImportRow,
|
||||
next: PostImportRow,
|
||||
): boolean =>
|
||||
previous.url !== next.url
|
||||
|| JSON.stringify (previous.attributes) !== JSON.stringify (next.attributes)
|
||||
|| JSON.stringify (previous.provenance) !== JSON.stringify (next.provenance)
|
||||
|| JSON.stringify (previous.tagSources ?? { }) !== JSON.stringify (next.tagSources ?? { })
|
||||
|
||||
|
||||
export const processableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
rows.filter (row => {
|
||||
if (row.importStatus === 'created')
|
||||
return false
|
||||
if (row.importStatus === 'skipped')
|
||||
return false
|
||||
if (row.importStatus === 'failed')
|
||||
return false
|
||||
if (hasValidationErrors (row))
|
||||
return false
|
||||
return row.importStatus == null || row.importStatus === 'pending'
|
||||
})
|
||||
|
||||
export const creatableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
processableImportRows (rows).filter (row => !(hasSkipReason (row)))
|
||||
|
||||
|
||||
export const reviewSummaryCounts = (rows: PostImportRow[]) => ({
|
||||
total: rows.length,
|
||||
submittable: rows.filter (row =>
|
||||
creatableImportRows ([row]).length > 0
|
||||
&& !(hasValidationErrors (row))).length,
|
||||
invalid: rows.filter (row => hasValidationErrors (row)).length,
|
||||
skipPlanned: rows.filter (row =>
|
||||
hasSkipReason (row)
|
||||
&& !(hasValidationErrors (row))
|
||||
&& row.importStatus !== 'created').length,
|
||||
created: rows.filter (row => row.importStatus === 'created').length,
|
||||
failed: rows.filter (row => row.importStatus === 'failed').length })
|
||||
|
||||
|
||||
export const resultSummaryCounts = (rows: PostImportRow[]) =>
|
||||
rows.reduce (
|
||||
(counts, row) => {
|
||||
if (hasValidationErrors (row))
|
||||
{
|
||||
++counts.invalid
|
||||
return counts
|
||||
}
|
||||
if (row.importStatus === 'created')
|
||||
{
|
||||
++counts.created
|
||||
return counts
|
||||
}
|
||||
if (row.importStatus === 'skipped')
|
||||
{
|
||||
++counts.skipped
|
||||
return counts
|
||||
}
|
||||
if (row.importStatus === 'failed')
|
||||
++counts.failed
|
||||
return counts
|
||||
},
|
||||
{ created: 0, skipped: 0, failed: 0, invalid: 0 })
|
||||
|
||||
|
||||
export const mergeValidatedImportRows = (
|
||||
current: PostImportRow[],
|
||||
validated: PostImportRow[],
|
||||
): PostImportRow[] => {
|
||||
const validatedMap = new Map (validated.map (row => [row.sourceRow, row]))
|
||||
return current.map (previous => {
|
||||
if (previous.importStatus === 'created')
|
||||
return previous
|
||||
|
||||
const row = validatedMap.get (previous.sourceRow)
|
||||
if (row == null)
|
||||
return previous
|
||||
|
||||
const fieldWarnings =
|
||||
Object.keys (row.fieldWarnings).length > 0 || row.metadataUrl !== previous.metadataUrl
|
||||
? { ...row.fieldWarnings }
|
||||
: { ...previous.fieldWarnings }
|
||||
for (const [field, origin] of Object.entries (row.provenance))
|
||||
{
|
||||
if (origin === 'manual')
|
||||
delete fieldWarnings[field]
|
||||
}
|
||||
|
||||
return {
|
||||
...previous,
|
||||
url: row.url,
|
||||
attributes: row.attributes,
|
||||
provenance: row.provenance,
|
||||
tagSources: row.tagSources,
|
||||
skipReason: row.skipReason,
|
||||
existingPostId: row.existingPostId,
|
||||
fieldWarnings,
|
||||
baseWarnings:
|
||||
row.baseWarnings.length > 0 || row.metadataUrl !== previous.metadataUrl
|
||||
? row.baseWarnings
|
||||
: previous.baseWarnings,
|
||||
validationErrors: row.validationErrors,
|
||||
status: row.status,
|
||||
metadataUrl: row.metadataUrl }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const mergePreviewImportRows = (
|
||||
current: PostImportRow[],
|
||||
preview: PostImportRow[],
|
||||
): PostImportRow[] => {
|
||||
const currentMap = new Map (current.map (row => [row.sourceRow, row]))
|
||||
return preview.map (row => {
|
||||
const previous = currentMap.get (row.sourceRow)
|
||||
if (previous == null)
|
||||
return row
|
||||
if (previous.importStatus === 'created')
|
||||
return previous
|
||||
|
||||
const mergedAttributes = { ...row.attributes }
|
||||
const mergedProvenance = { ...row.provenance }
|
||||
|
||||
for (const [field, origin] of Object.entries (previous.provenance))
|
||||
{
|
||||
if (origin !== 'manual' || field === 'url')
|
||||
continue
|
||||
if (field in previous.attributes)
|
||||
mergedAttributes[field] = previous.attributes[field]
|
||||
mergedProvenance[field] = 'manual'
|
||||
}
|
||||
|
||||
const mergedTagSources =
|
||||
previous.provenance.tags === 'manual'
|
||||
? {
|
||||
automatic: row.tagSources?.automatic ?? '',
|
||||
manual: previous.tagSources?.manual ?? String (previous.attributes.tags ?? '') }
|
||||
: row.tagSources
|
||||
|
||||
const nextRow = {
|
||||
...row,
|
||||
attributes: mergedAttributes,
|
||||
provenance: mergedProvenance,
|
||||
tagSources: mergedTagSources,
|
||||
skipReason: row.skipReason,
|
||||
existingPostId: row.existingPostId,
|
||||
createdPostId: previous.createdPostId,
|
||||
importStatus: previous.importStatus,
|
||||
importErrors: previous.importErrors }
|
||||
|
||||
if (rowChanged (previous, nextRow))
|
||||
{
|
||||
nextRow.importStatus = 'pending'
|
||||
nextRow.importErrors = undefined
|
||||
}
|
||||
return nextRow
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const mergeImportResults = (
|
||||
rows: PostImportRow[],
|
||||
results: PostImportResultRow[],
|
||||
): PostImportRow[] => {
|
||||
const resultMap = new Map (results.map (row => [row.sourceRow, row]))
|
||||
return rows.map (row => {
|
||||
const result = resultMap.get (row.sourceRow)
|
||||
return result
|
||||
? {
|
||||
...row,
|
||||
importStatus: result.status,
|
||||
createdPostId: result.post?.id,
|
||||
importErrors: result.errors }
|
||||
: row
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const retryImportRow = (
|
||||
rows: PostImportRow[],
|
||||
sourceRow: number,
|
||||
): PostImportRow[] =>
|
||||
rows.map (row =>
|
||||
row.sourceRow === sourceRow && row.importStatus === 'failed'
|
||||
? { ...row, importStatus: 'pending', importErrors: undefined }
|
||||
: row)
|
||||
新しい課題から参照
ユーザをブロックする