add put route for museums, and improve fixRadioSelection function to handle "null" strings

This commit is contained in:
juhanikat
2025-07-14 16:23:07 +03:00
parent f0fc6992f2
commit 3790fa3bec
8 changed files with 99 additions and 10 deletions
+19 -2
View File
@@ -1,6 +1,9 @@
import { Router } from 'express'
import { getAllMuseums, getMuseumDetails } from '../services/museum'
import { Router, Request } from 'express'
import { getAllMuseums, getMuseumDetails, validateEntireMuseum } from '../services/museum'
import { fixBigInt } from '../utils/common'
import { requireOneOf } from '../middlewares/authorizer'
import { Role, EditDataType, EditMetaData, RegionDetails, Museum } from '../../../frontend/src/shared/types'
import { writeMuseum } from '../services/write/museum'
const router = Router()
@@ -16,4 +19,18 @@ router.get('/:id', async (req, res) => {
return res.status(200).send(fixBigInt(museum))
})
router.put(
'/',
requireOneOf([Role.Admin]),
async (req: Request<object, object, { museum: EditDataType<Museum> & EditMetaData }>, res) => {
const { ...editedMuseum } = req.body.museum
const validationErrors = validateEntireMuseum({ ...editedMuseum })
if (validationErrors.length > 0) {
return res.status(403).send(validationErrors)
}
const museum = await writeMuseum(editedMuseum)
return res.status(200).send({ museum })
}
)
export default router
+14 -1
View File
@@ -1,5 +1,8 @@
import { Locality } from '../../../frontend/src/shared/types'
import { Locality, Museum, EditDataType, EditMetaData } from '../../../frontend/src/shared/types'
import { nowDb } from '../utils/db'
import { ValidationObject } from '../../../frontend/src/shared/validators/validator'
import Prisma from '../../prisma/generated/now_test_client'
import { validateMuseum } from '../../../frontend/src/shared/validators/museum'
export const getAllMuseums = async () => {
const result = await nowDb.com_mlist.findMany({})
@@ -31,3 +34,13 @@ export const getMuseumDetails = async (id: string) => {
return combined
}
export const validateEntireMuseum = (editedFields: EditDataType<Prisma.com_mlist> & EditMetaData) => {
const keys = Object.keys(editedFields)
const errors: ValidationObject[] = []
for (const key of keys) {
const error = validateMuseum(editedFields as EditDataType<Museum>, key as keyof Museum)
if (error.error) errors.push(error)
}
return errors
}
+30
View File
@@ -0,0 +1,30 @@
import { Museum, EditDataType } from '../../../../frontend/src/shared/types'
import { getFieldsOfTables, nowDb } from '../../utils/db'
import Prisma from '../../../prisma/generated/now_test_client'
import { filterAllowedKeys, fixRadioSelection } from './writeOperations/utils'
export const writeMuseum = async (museum: EditDataType<Museum>) => {
const allowedColumns = getFieldsOfTables(['com_mlist'])
const filteredMuseum = filterAllowedKeys(museum, allowedColumns) as Prisma.com_mlist
let museumId: string
if (!filteredMuseum.museum) {
const newMuseum = await nowDb.com_mlist.create({
data: filteredMuseum,
})
museumId = newMuseum.museum
} else {
await nowDb.com_mlist.update({
where: { museum: museum.museum },
data: {
...filteredMuseum,
used_morph: fixRadioSelection(filteredMuseum.used_morph),
used_now: fixRadioSelection(filteredMuseum.used_now),
used_gene: fixRadioSelection(filteredMuseum.used_gene),
},
})
museumId = filteredMuseum.museum
}
return museumId
}
@@ -46,6 +46,7 @@ export const makeListRemoved = (list: Editable<Record<string, unknown>>[]) => {
export const fixRadioSelection = (value: unknown) => {
if (typeof value === 'string') {
if (value === 'null') return null
return value === 'true' ? true : false
}
if (typeof value === 'boolean') return value
@@ -1,16 +1,21 @@
import { useGetMuseumDetailsQuery } from '../../redux/museumReducer'
import { useEditMuseumMutation, useGetMuseumDetailsQuery } from '../../redux/museumReducer'
import { DetailView, TabType } from '../DetailView/DetailView'
import { MuseumInfoTab } from './Tabs/MuseumInfoTab'
import { emptyMuseum } from '../DetailView/common/defaultValues'
import { validateMuseum } from '@/shared/validators/museum'
import { useParams } from 'react-router-dom'
import { useNavigate, useParams } from 'react-router-dom'
import { CircularProgress } from '@mui/material'
import { Museum } from '@/shared/types'
import { Museum, EditDataType, ValidationErrors } from '@/shared/types'
import { LocalityTab } from './Tabs/LocalityTab'
import { useNotify } from '@/hooks/notification'
export const MuseumDetails = () => {
const { id } = useParams()
const isNew = id === 'new'
const { isError, isFetching, data } = useGetMuseumDetailsQuery(id!)
const [editMuseumRequest, { isLoading: mutationLoading }] = useEditMuseumMutation()
const notify = useNotify()
const navigate = useNavigate()
const tabs: TabType[] = [
{
@@ -24,16 +29,27 @@ export const MuseumDetails = () => {
]
if (isError) return <div>Error loading data</div>
if (isFetching || !data) return <CircularProgress />
if (isFetching || (!data && !isNew) || mutationLoading) return <CircularProgress />
if (data) {
document.title = `Museum - ${data.institution}`
}
const onWrite = async (editData: EditDataType<Museum>) => {
try {
const { museum } = await editMuseumRequest(editData).unwrap()
notify('Saved region successfully.')
setTimeout(() => navigate(`/museum/${museum}`), 15)
} catch (e) {
const error = e as ValidationErrors
notify('Following validators failed: ' + error.data.map(e => e.name).join(', '), 'error')
}
}
return (
<DetailView<Museum>
tabs={tabs}
data={!data ? emptyMuseum : data}
onWrite={undefined}
onWrite={onWrite}
isNew={false}
validator={validateMuseum}
deleteFunction={undefined}
@@ -4,6 +4,8 @@ import { Museum } from '@/shared/types'
export const MuseumInfoTab = () => {
const { textField, radioSelection } = useDetailContext<Museum>()
const { editData } = useDetailContext()
const museumInfo = [
['Institution', textField('institution')],
['Alt. name', textField('alt_int_name')],
+2
View File
@@ -65,6 +65,8 @@ export const api = createApi({
'timebounds',
'region',
'regions',
'museum',
'museums',
'person',
'persons',
'author',
+10 -2
View File
@@ -1,4 +1,4 @@
import { Museum } from '@/shared/types'
import { Museum, EditDataType } from '@/shared/types'
import { api } from './api'
const museumsApi = api.injectEndpoints({
@@ -14,7 +14,15 @@ const museumsApi = api.injectEndpoints({
}),
providesTags: result => (result ? [{ type: 'museum', id: result.museum }] : []),
}),
editMuseum: builder.mutation<Museum, EditDataType<Museum>>({
query: museum => ({
url: `/museum`,
method: 'PUT',
body: { museum },
}),
invalidatesTags: (result, _error, { museum }) => (result ? [{ type: 'museum', id: museum }, 'museums'] : []),
}),
}),
})
export const { useGetAllMuseumsQuery, useGetMuseumDetailsQuery } = museumsApi
export const { useGetAllMuseumsQuery, useGetMuseumDetailsQuery, useEditMuseumMutation } = museumsApi