mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Harden reference date reads
This commit is contained in:
@@ -20,6 +20,7 @@ import { logDb, nowDb } from '../utils/db'
|
|||||||
import { validateCollectingMethodValues } from '../utils/validation/collectingMethodValues'
|
import { validateCollectingMethodValues } from '../utils/validation/collectingMethodValues'
|
||||||
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
||||||
import { getReferenceDetails } from './reference'
|
import { getReferenceDetails } from './reference'
|
||||||
|
import { addNullExactDateToReferenceJoins, referenceWithoutExactDateSelect } from './utils/referenceDate'
|
||||||
|
|
||||||
const normalizeNumberField = (value: unknown) => {
|
const normalizeNumberField = (value: unknown) => {
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
@@ -259,34 +260,7 @@ export const getLocalityDetails = async (id: number, user: User | undefined) =>
|
|||||||
now_lr: {
|
now_lr: {
|
||||||
include: {
|
include: {
|
||||||
ref_ref: {
|
ref_ref: {
|
||||||
select: {
|
select: referenceWithoutExactDateSelect,
|
||||||
rid: true,
|
|
||||||
ref_type_id: true,
|
|
||||||
journal_id: true,
|
|
||||||
title_primary: true,
|
|
||||||
date_primary: true,
|
|
||||||
volume: true,
|
|
||||||
issue: true,
|
|
||||||
start_page: true,
|
|
||||||
end_page: true,
|
|
||||||
publisher: true,
|
|
||||||
pub_place: true,
|
|
||||||
title_secondary: true,
|
|
||||||
date_secondary: true,
|
|
||||||
title_series: true,
|
|
||||||
issn_isbn: true,
|
|
||||||
ref_abstract: true,
|
|
||||||
web_url: true,
|
|
||||||
misc_1: true,
|
|
||||||
misc_2: true,
|
|
||||||
gen_notes: true,
|
|
||||||
printed_language: true,
|
|
||||||
used_morph: true,
|
|
||||||
used_now: true,
|
|
||||||
used_gene: true,
|
|
||||||
ref_authors: true,
|
|
||||||
ref_journal: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -315,13 +289,7 @@ export const getLocalityDetails = async (id: number, user: User | undefined) =>
|
|||||||
...lau,
|
...lau,
|
||||||
lau_coordinator: getPersonDisplayName(coordinatorPerson, lau.lau_coordinator),
|
lau_coordinator: getPersonDisplayName(coordinatorPerson, lau.lau_coordinator),
|
||||||
lau_authorizer: getPersonDisplayName(authorizerPerson, lau.lau_authorizer),
|
lau_authorizer: getPersonDisplayName(authorizerPerson, lau.lau_authorizer),
|
||||||
now_lr: lau.now_lr.map(lr => ({
|
now_lr: addNullExactDateToReferenceJoins(lau.now_lr),
|
||||||
...lr,
|
|
||||||
ref_ref: {
|
|
||||||
...lr.ref_ref,
|
|
||||||
exact_date: null,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
updates,
|
updates,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { AccessError } from '../middlewares/authorizer'
|
|||||||
import { logDb, nowDb } from '../utils/db'
|
import { logDb, nowDb } from '../utils/db'
|
||||||
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
||||||
import { generateOccurrenceDetailSql } from './queries/crossSearchQuery'
|
import { generateOccurrenceDetailSql } from './queries/crossSearchQuery'
|
||||||
|
import { addNullExactDateToReferenceJoins, referenceWithoutExactDateSelect } from './utils/referenceDate'
|
||||||
|
|
||||||
const getAllowedLocalities = async (user: User) => {
|
const getAllowedLocalities = async (user: User) => {
|
||||||
const usersProjects = await nowDb.now_proj_people.findMany({
|
const usersProjects = await nowDb.now_proj_people.findMany({
|
||||||
@@ -119,44 +120,6 @@ type OccurrenceUpdate = {
|
|||||||
updates: OccurrenceLogRow[]
|
updates: OccurrenceLogRow[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const referenceWithoutExactDateSelect = {
|
|
||||||
rid: true,
|
|
||||||
ref_type_id: true,
|
|
||||||
journal_id: true,
|
|
||||||
title_primary: true,
|
|
||||||
date_primary: true,
|
|
||||||
volume: true,
|
|
||||||
issue: true,
|
|
||||||
start_page: true,
|
|
||||||
end_page: true,
|
|
||||||
publisher: true,
|
|
||||||
pub_place: true,
|
|
||||||
title_secondary: true,
|
|
||||||
date_secondary: true,
|
|
||||||
title_series: true,
|
|
||||||
issn_isbn: true,
|
|
||||||
ref_abstract: true,
|
|
||||||
web_url: true,
|
|
||||||
misc_1: true,
|
|
||||||
misc_2: true,
|
|
||||||
gen_notes: true,
|
|
||||||
printed_language: true,
|
|
||||||
used_morph: true,
|
|
||||||
used_now: true,
|
|
||||||
used_gene: true,
|
|
||||||
ref_authors: true,
|
|
||||||
ref_journal: true,
|
|
||||||
} as const
|
|
||||||
|
|
||||||
const addNullExactDateToReferences = <T extends { ref_ref: object }>(references: T[]) =>
|
|
||||||
references.map(reference => ({
|
|
||||||
...reference,
|
|
||||||
ref_ref: {
|
|
||||||
...reference.ref_ref,
|
|
||||||
exact_date: null,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
const stringifyLogValue = (value: unknown) => {
|
const stringifyLogValue = (value: unknown) => {
|
||||||
if (value === null || value === undefined) return ''
|
if (value === null || value === undefined) return ''
|
||||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value)
|
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value)
|
||||||
@@ -271,7 +234,7 @@ const getOccurrenceUpdates = async (lid: number, speciesId: number) => {
|
|||||||
update.lau_coordinator
|
update.lau_coordinator
|
||||||
),
|
),
|
||||||
occ_comment: update.lau_comment ?? '',
|
occ_comment: update.lau_comment ?? '',
|
||||||
references: addNullExactDateToReferences(update.now_lr) as unknown as AnyReference[],
|
references: addNullExactDateToReferenceJoins(update.now_lr) as unknown as AnyReference[],
|
||||||
updates: nowLsLogs.filter(logRow => logRow.luid === update.luid),
|
updates: nowLsLogs.filter(logRow => logRow.luid === update.luid),
|
||||||
})),
|
})),
|
||||||
...speciesUpdates.map(update => ({
|
...speciesUpdates.map(update => ({
|
||||||
@@ -285,7 +248,7 @@ const getOccurrenceUpdates = async (lid: number, speciesId: number) => {
|
|||||||
update.sau_coordinator
|
update.sau_coordinator
|
||||||
),
|
),
|
||||||
occ_comment: update.sau_comment ?? '',
|
occ_comment: update.sau_comment ?? '',
|
||||||
references: addNullExactDateToReferences(update.now_sr) as unknown as AnyReference[],
|
references: addNullExactDateToReferenceJoins(update.now_sr) as unknown as AnyReference[],
|
||||||
updates: nowLsLogs.filter(logRow => logRow.suid === update.suid),
|
updates: nowLsLogs.filter(logRow => logRow.suid === update.suid),
|
||||||
})),
|
})),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -7,6 +7,20 @@ import {
|
|||||||
} from './referenceValidation'
|
} from './referenceValidation'
|
||||||
import { Role, User } from '../../../frontend/src/shared/types'
|
import { Role, User } from '../../../frontend/src/shared/types'
|
||||||
import { getIdsOfUsersProjects } from './locality'
|
import { getIdsOfUsersProjects } from './locality'
|
||||||
|
import { referenceWithoutExactDateSelect } from './utils/referenceDate'
|
||||||
|
|
||||||
|
type RawReferenceExactDate = {
|
||||||
|
exact_date: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizeRawExactDate = (value: string | null | undefined): string | null => {
|
||||||
|
if (!value) return null
|
||||||
|
const date = value.slice(0, 10)
|
||||||
|
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date)
|
||||||
|
if (!match) return null
|
||||||
|
if (match[2] === '00' || match[3] === '00') return null
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
export const getAllReferences = async () => {
|
export const getAllReferences = async () => {
|
||||||
const result = await nowDb.ref_ref.findMany({
|
const result = await nowDb.ref_ref.findMany({
|
||||||
@@ -41,22 +55,20 @@ export const getAllReferences = async () => {
|
|||||||
export const getReferenceDetails = async (id: number, _user?: User) => {
|
export const getReferenceDetails = async (id: number, _user?: User) => {
|
||||||
const result = await nowDb.ref_ref.findUnique({
|
const result = await nowDb.ref_ref.findUnique({
|
||||||
where: { rid: id },
|
where: { rid: id },
|
||||||
include: { ref_authors: true, ref_journal: true },
|
select: referenceWithoutExactDateSelect,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
//changing exact_date to yyyy-mm-dd string since frontend uses that + we don't want to display ISO string in frontend
|
const exactDateRows = await nowDb.$queryRaw<RawReferenceExactDate[]>`
|
||||||
if (result && result.exact_date) {
|
SELECT CAST(exact_date AS CHAR) AS exact_date
|
||||||
const date = new Date(result.exact_date)
|
FROM ref_ref
|
||||||
const formattedDate = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
|
WHERE rid = ${id}
|
||||||
|
`
|
||||||
|
|
||||||
return { ...result, exact_date: formattedDate }
|
return { ...result, exact_date: normalizeRawExactDate(exactDateRows[0]?.exact_date) }
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch localities that have been updated by the given reference id
|
// Fetch localities that have been updated by the given reference id
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { ValidationObject, referenceValidator } from '../../../frontend/src/shar
|
|||||||
import { getReferenceDetails } from './reference'
|
import { getReferenceDetails } from './reference'
|
||||||
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
||||||
import { TabListQueryOptions } from './tabularQuery'
|
import { TabListQueryOptions } from './tabularQuery'
|
||||||
|
import { addNullExactDateToReferenceJoins, referenceWithoutExactDateSelect } from './utils/referenceDate'
|
||||||
|
|
||||||
export const getAllTimeBounds = async () => {
|
export const getAllTimeBounds = async () => {
|
||||||
const result = await nowDb.now_tu_bound.findMany({
|
const result = await nowDb.now_tu_bound.findMany({
|
||||||
@@ -30,10 +31,7 @@ export const getTimeBoundDetails = async (id: number) => {
|
|||||||
now_br: {
|
now_br: {
|
||||||
include: {
|
include: {
|
||||||
ref_ref: {
|
ref_ref: {
|
||||||
include: {
|
select: referenceWithoutExactDateSelect,
|
||||||
ref_authors: true,
|
|
||||||
ref_journal: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -61,6 +59,7 @@ export const getTimeBoundDetails = async (id: number) => {
|
|||||||
...bau,
|
...bau,
|
||||||
bau_coordinator: getPersonDisplayName(coordinatorPerson, bau.bau_coordinator),
|
bau_coordinator: getPersonDisplayName(coordinatorPerson, bau.bau_coordinator),
|
||||||
bau_authorizer: getPersonDisplayName(authorizerPerson, bau.bau_authorizer),
|
bau_authorizer: getPersonDisplayName(authorizerPerson, bau.bau_authorizer),
|
||||||
|
now_br: addNullExactDateToReferenceJoins(bau.now_br),
|
||||||
updates,
|
updates,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { validateTimeUnit } from '../../../frontend/src/shared/validators/timeUn
|
|||||||
import { getReferenceDetails } from './reference'
|
import { getReferenceDetails } from './reference'
|
||||||
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
import { buildPersonLookupByInitials, getPersonDisplayName, getPersonFromLookup } from './utils/person'
|
||||||
import { TabListQueryOptions } from './tabularQuery'
|
import { TabListQueryOptions } from './tabularQuery'
|
||||||
|
import { addNullExactDateToReferenceJoins, referenceWithoutExactDateSelect } from './utils/referenceDate'
|
||||||
|
|
||||||
export const getAllTimeUnits = async () => {
|
export const getAllTimeUnits = async () => {
|
||||||
const result = await nowDb.now_time_unit.findMany({
|
const result = await nowDb.now_time_unit.findMany({
|
||||||
@@ -53,10 +54,7 @@ export const getTimeUnitDetails = async (id: string) => {
|
|||||||
now_tr: {
|
now_tr: {
|
||||||
include: {
|
include: {
|
||||||
ref_ref: {
|
ref_ref: {
|
||||||
include: {
|
select: referenceWithoutExactDateSelect,
|
||||||
ref_authors: true,
|
|
||||||
ref_journal: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -85,6 +83,7 @@ export const getTimeUnitDetails = async (id: string) => {
|
|||||||
...tau,
|
...tau,
|
||||||
tau_coordinator: getPersonDisplayName(coordinatorPerson, tau.tau_coordinator),
|
tau_coordinator: getPersonDisplayName(coordinatorPerson, tau.tau_coordinator),
|
||||||
tau_authorizer: getPersonDisplayName(authorizerPerson, tau.tau_authorizer),
|
tau_authorizer: getPersonDisplayName(authorizerPerson, tau.tau_authorizer),
|
||||||
|
now_tr: addNullExactDateToReferenceJoins(tau.now_tr),
|
||||||
updates,
|
updates,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
export const referenceWithoutExactDateSelect = {
|
||||||
|
rid: true,
|
||||||
|
ref_type_id: true,
|
||||||
|
journal_id: true,
|
||||||
|
title_primary: true,
|
||||||
|
date_primary: true,
|
||||||
|
volume: true,
|
||||||
|
issue: true,
|
||||||
|
start_page: true,
|
||||||
|
end_page: true,
|
||||||
|
publisher: true,
|
||||||
|
pub_place: true,
|
||||||
|
title_secondary: true,
|
||||||
|
date_secondary: true,
|
||||||
|
title_series: true,
|
||||||
|
issn_isbn: true,
|
||||||
|
ref_abstract: true,
|
||||||
|
web_url: true,
|
||||||
|
misc_1: true,
|
||||||
|
misc_2: true,
|
||||||
|
gen_notes: true,
|
||||||
|
printed_language: true,
|
||||||
|
used_morph: true,
|
||||||
|
used_now: true,
|
||||||
|
used_gene: true,
|
||||||
|
ref_authors: true,
|
||||||
|
ref_journal: true,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const addNullExactDateToReference = <T extends object>(reference: T) => ({
|
||||||
|
...reference,
|
||||||
|
exact_date: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const addNullExactDateToReferenceJoins = <T extends { ref_ref: object }>(references: T[]) =>
|
||||||
|
references.map(reference => ({
|
||||||
|
...reference,
|
||||||
|
ref_ref: addNullExactDateToReference(reference.ref_ref),
|
||||||
|
}))
|
||||||
Reference in New Issue
Block a user