Merge branch 'main' into update-region-docs

This commit is contained in:
Kari Lintulaakso
2025-02-27 10:39:48 +02:00
committed by GitHub
7 changed files with 150 additions and 3 deletions
@@ -0,0 +1,40 @@
import { beforeEach, beforeAll, afterAll, describe, it, expect } from '@jest/globals'
import { login, logout, resetDatabase, send, resetDatabaseTimeout } from '../utils'
import { pool } from '../../utils/db'
describe('Deleting a region works', () => {
beforeAll(async () => {
await resetDatabase()
}, resetDatabaseTimeout)
beforeEach(async () => {
await login()
})
afterAll(async () => {
await pool.end()
})
it('Deleting returns correct status and after that is not found on request', async () => {
const deleteResult = await send<{ id: number }>('region/1', 'DELETE')
expect(deleteResult.status).toEqual(200)
const getResult = await send('region/1', 'GET')
expect(getResult.status).toEqual(404) // 'Region response status was not 404 after deletion'
})
it('Deleting fails without permissions', async () => {
logout()
const deleteResultNoPerm = await send<{ id: number }>('region/2', 'DELETE')
expect(deleteResultNoPerm.status).toEqual(403)
await login('testEr')
const deleteResultEr = await send<{ id: number }>('region/2', 'DELETE')
expect(deleteResultEr.status).toEqual(403)
await login('testEu')
const deleteResultEu = await send<{ id: number }>('region/2', 'DELETE')
expect(deleteResultEu.status).toEqual(403)
await login()
const getResultSu = await send('region/2', 'GET')
expect(getResultSu.status).toEqual(200)
})
})
+34
View File
@@ -0,0 +1,34 @@
import { beforeAll, afterAll, describe, it, expect, beforeEach } from '@jest/globals'
import { login, logout, resetDatabase, send, resetDatabaseTimeout } from '../utils'
import { pool } from '../../utils/db'
describe('Deleting a region works', () => {
beforeAll(async () => {
await resetDatabase()
}, resetDatabaseTimeout)
beforeEach(async () => {
await login()
})
afterAll(async () => {
await pool.end()
})
it('Getting region data succeeds with admin privileges', async () => {
const getResultSu = await send('region/2', 'GET')
expect(getResultSu.status).toEqual(200)
})
it('Getting region data fails without permissions', async () => {
logout()
const getResultNoPerm = await send('region/2', 'GET')
expect(getResultNoPerm.status).toEqual(403)
await login('testEr')
const getResultEr = await send('region/2', 'GET')
expect(getResultEr.status).toEqual(403)
await login('testEu')
const getResultEu = await send('region/2', 'GET')
expect(getResultEu.status).toEqual(403)
})
})
+7 -1
View File
@@ -2,7 +2,7 @@ import { Router, Request } from 'express'
import { getAllRegions, getRegionDetails, validateEntireRegion } from '../services/region'
import { requireOneOf } from '../middlewares/authorizer'
import { Role, EditDataType, EditMetaData, RegionDetails } from '../../../frontend/src/shared/types'
import { writeRegion } from '../services/write/region'
import { writeRegion, deleteRegion } from '../services/write/region'
const router = Router()
@@ -32,4 +32,10 @@ router.put(
}
)
router.delete('/:id', requireOneOf([Role.Admin]), async (req, res) => {
const id = parseInt(req.params.id)
await deleteRegion(id)
res.status(200).send()
})
export default router
+25
View File
@@ -1,6 +1,7 @@
import { EditDataType, RegionCountry, RegionDetails, RegionCoordinator } from '../../../../frontend/src/shared/types'
import Prisma from '../../../prisma/generated/now_test_client'
import { nowDb, getFieldsOfTables } from '../../utils/db'
import { getRegionDetails } from '../region'
import { filterAllowedKeys } from './writeOperations/utils'
export const writeRegionCountries = async (regionId: number, countries: EditDataType<RegionCountry[]>) => {
@@ -72,3 +73,27 @@ export const writeRegion = async (region: EditDataType<RegionDetails>) => {
return regionId
}
export const deleteRegion = async (regionId: number) => {
const region = await getRegionDetails(regionId)
if (!region) throw new Error('Region not found')
await nowDb.$transaction(async prisma => {
await prisma.now_reg_coord_country.deleteMany({
where: { reg_coord_id: regionId },
})
await prisma.now_reg_coord_people.deleteMany({
where: { reg_coord_id: regionId },
})
try {
await prisma.now_reg_coord.delete({
where: { reg_coord_id: regionId },
})
} catch (error) {
throw new Error('Failed to delete the region')
}
})
}
+17
View File
@@ -110,3 +110,20 @@ describe('Editing a region', () => {
cy.get('[id=country-add-button]').should('be.disabled')
})
})
describe('Deleting a region', () => {
beforeEach('Login as admin', () => {
cy.login('testSu')
})
it('works and returns user to table view', () => {
cy.visit('/region/1')
cy.get('[id=delete-button]').should('exist').click()
cy.on('window:confirm', str => {
expect(str).to.eq('Are you sure you want to delete this item? This operation cannot be undone.')
// this automatically clicks the OK button and returns to table view
})
cy.contains('region 44524b6e')
cy.contains('region 4452477e').should('not.exist')
})
})
@@ -1,11 +1,12 @@
import { useNavigate, useParams } from 'react-router-dom'
import { useEditRegionMutation, useGetRegionDetailsQuery } from '../../redux/regionReducer'
import { useEditRegionMutation, useGetRegionDetailsQuery, useDeleteRegionMutation } from '../../redux/regionReducer'
import { CircularProgress } from '@mui/material'
import { DetailView, TabType } from '../DetailView/DetailView'
import { CoordinatorTab } from './Tabs/CoordinatorTab'
import { EditDataType, RegionDetails as RegionDetailsType, ValidationErrors } from '@/shared/types'
import { useNotify } from '@/hooks/notification'
import { validateRegion } from '@/shared/validators/region'
import { useEffect } from 'react'
import { emptyRegion } from '../DetailView/common/defaultValues'
export const RegionDetails = () => {
@@ -13,10 +14,21 @@ export const RegionDetails = () => {
const isNew = id === 'new'
const { isLoading, isError, data } = useGetRegionDetailsQuery(id!, { skip: isNew })
const [editRegionRequest, { isLoading: mutationLoading }] = useEditRegionMutation()
const [deleteMutation, { isSuccess: deleteSuccess, isError: deleteError }] = useDeleteRegionMutation()
const notify = useNotify()
const navigate = useNavigate()
useEffect(() => {
if (deleteSuccess) {
notify('Deleted item successfully.')
navigate('/region')
} else if (deleteError) {
notify('Could not delete item. Error happened.', 'error')
}
}, [deleteSuccess, deleteError, notify, navigate])
if (isError) return <div>Error loading data</div>
if (isLoading || (!data && !isNew) || mutationLoading) return <CircularProgress />
document.title = isNew ? 'New region' : data!.region
@@ -32,6 +44,10 @@ export const RegionDetails = () => {
}
}
const deleteFunction = async () => {
await deleteMutation(parseInt(id!)).unwrap()
}
const tabs: TabType[] = [
{
title: 'Regional',
@@ -46,6 +62,7 @@ export const RegionDetails = () => {
data={isNew ? emptyRegion : data!}
onWrite={onWrite}
validator={validateRegion}
deleteFunction={deleteFunction}
/>
)
}
+9 -1
View File
@@ -24,7 +24,15 @@ const regionsApi = api.injectEndpoints({
invalidatesTags: (result, _error, { reg_coord_id }) =>
result ? [{ type: 'region', id: reg_coord_id }, 'regions'] : [],
}),
deleteRegion: builder.mutation<void, number>({
query: id => ({
url: `/region/${id}`,
method: 'DELETE',
}),
invalidatesTags: ['regions'],
}),
}),
})
export const { useGetAllRegionsQuery, useGetRegionDetailsQuery, useEditRegionMutation } = regionsApi
export const { useGetAllRegionsQuery, useGetRegionDetailsQuery, useEditRegionMutation, useDeleteRegionMutation } =
regionsApi