このコミットが含まれているのは:
@@ -7,18 +7,14 @@ const hasSkipReason = (row: PostImportRow): boolean =>
|
||||
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 ?? { })
|
||||
|
||||
const buildResetSnapshot = (row: PostImportRow) => ({
|
||||
url: row.url,
|
||||
attributes: row.attributes })
|
||||
attributes: { ...row.attributes },
|
||||
provenance: { ...row.provenance },
|
||||
tagSources: {
|
||||
automatic: row.tagSources?.automatic ?? '',
|
||||
manual: row.tagSources?.manual ?? '' },
|
||||
metadataUrl: row.metadataUrl })
|
||||
|
||||
|
||||
export const processableImportRows = (rows: PostImportRow[]): PostImportRow[] =>
|
||||
@@ -43,23 +39,14 @@ export const reviewSummaryCounts = (rows: PostImportRow[]) => ({
|
||||
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 })
|
||||
processableImportRows ([row]).length > 0
|
||||
&& hasSkipReason (row)).length })
|
||||
|
||||
|
||||
export const resultSummaryCounts = (rows: PostImportRow[]) =>
|
||||
rows.reduce (
|
||||
(counts, row) => {
|
||||
if (hasValidationErrors (row))
|
||||
{
|
||||
++counts.invalid
|
||||
return counts
|
||||
}
|
||||
if (row.importStatus === 'created')
|
||||
{
|
||||
++counts.created
|
||||
@@ -74,7 +61,7 @@ export const resultSummaryCounts = (rows: PostImportRow[]) =>
|
||||
++counts.failed
|
||||
return counts
|
||||
},
|
||||
{ created: 0, skipped: 0, failed: 0, invalid: 0 })
|
||||
{ created: 0, skipped: 0, failed: 0 })
|
||||
|
||||
|
||||
export const mergeValidatedImportRows = (
|
||||
@@ -83,7 +70,11 @@ export const mergeValidatedImportRows = (
|
||||
): PostImportRow[] => {
|
||||
const validatedMap = new Map (validated.map (row => [row.sourceRow, row]))
|
||||
return current.map (previous => {
|
||||
if (previous.importStatus === 'created')
|
||||
if (
|
||||
previous.importStatus === 'created'
|
||||
|| previous.importStatus === 'skipped'
|
||||
|| previous.importStatus === 'failed'
|
||||
)
|
||||
return previous
|
||||
|
||||
const row = validatedMap.get (previous.sourceRow)
|
||||
@@ -124,59 +115,6 @@ export const mergeValidatedImportRows = (
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
resetSnapshot: row.resetSnapshot,
|
||||
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[],
|
||||
@@ -193,13 +131,15 @@ export const mergeImportResults = (
|
||||
return {
|
||||
...row,
|
||||
importStatus: 'created',
|
||||
createdPostId: result.post?.id,
|
||||
skipReason: undefined,
|
||||
createdPostId: result.post.id,
|
||||
existingPostId: undefined,
|
||||
importErrors: result.errors }
|
||||
case 'skipped':
|
||||
return {
|
||||
...row,
|
||||
importStatus: 'skipped',
|
||||
skipReason: 'existing',
|
||||
createdPostId: undefined,
|
||||
existingPostId: result.existingPostId,
|
||||
importErrors: result.errors }
|
||||
@@ -207,6 +147,7 @@ export const mergeImportResults = (
|
||||
return {
|
||||
...row,
|
||||
importStatus: 'failed',
|
||||
skipReason: undefined,
|
||||
createdPostId: undefined,
|
||||
existingPostId: undefined,
|
||||
importErrors: result.errors }
|
||||
|
||||
@@ -150,10 +150,27 @@ const sanitiseResetSnapshot = (value: unknown): PostImportResetSnapshot | null =
|
||||
if (!(Object.values (value.attributes).every (entry =>
|
||||
typeof entry === 'string' || typeof entry === 'number')))
|
||||
return null
|
||||
if (!(isPlainObject (value.provenance)))
|
||||
return null
|
||||
if (!(hasOnlyKeys (value.provenance, PROVENANCE_KEYS)))
|
||||
return null
|
||||
if (!(Object.values (value.provenance).every (origin => isValidOrigin (origin))))
|
||||
return null
|
||||
if (!(isPlainObject (value.tagSources)))
|
||||
return null
|
||||
if (!(hasOnlyKeys (value.tagSources, TAG_SOURCE_KEYS)))
|
||||
return null
|
||||
if (!(Object.values (value.tagSources).every (_1 => typeof _1 === 'string')))
|
||||
return null
|
||||
if (value.metadataUrl != null && typeof value.metadataUrl !== 'string')
|
||||
return null
|
||||
|
||||
return {
|
||||
url: value.url,
|
||||
attributes: value.attributes as Record<string, string | number> }
|
||||
attributes: value.attributes as Record<string, string | number>,
|
||||
provenance: value.provenance as Record<string, PostImportOrigin>,
|
||||
tagSources: value.tagSources as Record<PostImportOrigin, string>,
|
||||
metadataUrl: value.metadataUrl as string | undefined }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,8 +10,11 @@ export type PostImportResultStatus = 'created' | 'skipped' | 'failed'
|
||||
export type PostImportAttributeValue = string | number
|
||||
|
||||
export type PostImportResetSnapshot = {
|
||||
url: string
|
||||
attributes: Record<string, PostImportAttributeValue> }
|
||||
url: string
|
||||
attributes: Record<string, PostImportAttributeValue>
|
||||
provenance: Record<string, PostImportOrigin>
|
||||
tagSources: Record<PostImportOrigin, string>
|
||||
metadataUrl?: string }
|
||||
|
||||
export type PostImportRow = {
|
||||
sourceRow: number
|
||||
@@ -31,12 +34,21 @@ export type PostImportRow = {
|
||||
createdPostId?: number
|
||||
importStatus?: PostImportStatus }
|
||||
|
||||
export type PostImportResultRow = {
|
||||
sourceRow: number
|
||||
status: PostImportResultStatus
|
||||
post?: { id: number }
|
||||
existingPostId?: number
|
||||
errors?: Record<string, string[]> }
|
||||
export type PostImportResultRow =
|
||||
| {
|
||||
sourceRow: number
|
||||
status: 'created'
|
||||
post: { id: number }
|
||||
errors?: Record<string, string[]> }
|
||||
| {
|
||||
sourceRow: number
|
||||
status: 'skipped'
|
||||
existingPostId: number
|
||||
errors?: Record<string, string[]> }
|
||||
| {
|
||||
sourceRow: number
|
||||
status: 'failed'
|
||||
errors?: Record<string, string[]> }
|
||||
|
||||
export type PostImportSession = {
|
||||
version: number
|
||||
|
||||
新しい課題から参照
ユーザをブロックする