feat(admin): implement delete functionality for Falukant regions and update UI components
This commit is contained in:
@@ -57,6 +57,7 @@ class AdminController {
|
||||
this.getFalukantAllRegions = this.getFalukantAllRegions.bind(this);
|
||||
this.getFalukantRegionTypes = this.getFalukantRegionTypes.bind(this);
|
||||
this.createFalukantRegion = this.createFalukantRegion.bind(this);
|
||||
this.deleteFalukantRegion = this.deleteFalukantRegion.bind(this);
|
||||
this.updateFalukantRegionMap = this.updateFalukantRegionMap.bind(this);
|
||||
this.getRegionDistances = this.getRegionDistances.bind(this);
|
||||
this.upsertRegionDistance = this.upsertRegionDistance.bind(this);
|
||||
@@ -622,6 +623,19 @@ class AdminController {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteFalukantRegion(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
const result = await AdminService.deleteFalukantRegion(userId, req.params.id);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
const status = error.message === 'noaccess' ? 403
|
||||
: (['regionNotFound'].includes(error.message) ? 404 : 400);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async updateFalukantRegionMap(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Older generated SRS data contained the number word "Baynte" as the
|
||||
* currency phrase "20 Peso". Baynte itself means twenty, so the expected
|
||||
* answer must be the number without a currency unit.
|
||||
*/
|
||||
module.exports = {
|
||||
async up(queryInterface) {
|
||||
await queryInterface.sequelize.query(`
|
||||
WITH affected AS (
|
||||
SELECT
|
||||
id,
|
||||
user_id,
|
||||
course_id,
|
||||
lesson_id,
|
||||
direction,
|
||||
CASE
|
||||
WHEN LOWER(TRIM(learning)) = 'baynte' THEN 'baynte'
|
||||
ELSE '20'
|
||||
END AS corrected_learning,
|
||||
CASE
|
||||
WHEN LOWER(TRIM(reference)) = 'baynte' THEN 'baynte'
|
||||
ELSE '20'
|
||||
END AS corrected_reference
|
||||
FROM community.vocab_srs_item
|
||||
WHERE (LOWER(TRIM(learning)) = 'baynte' AND LOWER(TRIM(reference)) IN ('20 peso', '20 pesos'))
|
||||
OR (LOWER(TRIM(reference)) = 'baynte' AND LOWER(TRIM(learning)) IN ('20 peso', '20 pesos'))
|
||||
),
|
||||
keyed AS (
|
||||
SELECT
|
||||
affected.*,
|
||||
ENCODE(DIGEST(CONCAT_WS(
|
||||
'|',
|
||||
course_id::text,
|
||||
COALESCE(lesson_id::text, 'course'),
|
||||
UPPER(direction),
|
||||
corrected_learning,
|
||||
corrected_reference
|
||||
), 'sha1'), 'hex') AS corrected_item_key
|
||||
FROM affected
|
||||
)
|
||||
UPDATE community.vocab_srs_item item
|
||||
SET learning = keyed.corrected_learning,
|
||||
reference = keyed.corrected_reference,
|
||||
item_key = keyed.corrected_item_key,
|
||||
updated_at = NOW()
|
||||
FROM keyed
|
||||
WHERE item.id = keyed.id
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM community.vocab_srs_item duplicate
|
||||
WHERE duplicate.user_id = keyed.user_id
|
||||
AND duplicate.item_key = keyed.corrected_item_key
|
||||
AND duplicate.id <> keyed.id
|
||||
);
|
||||
`);
|
||||
},
|
||||
|
||||
async down() {
|
||||
// The old answer was semantically incorrect and must not be restored.
|
||||
},
|
||||
};
|
||||
@@ -65,6 +65,7 @@ router.get('/falukant/region-types', authenticate, adminController.getFalukantRe
|
||||
router.get('/falukant/regions', authenticate, adminController.getFalukantRegions);
|
||||
router.get('/falukant/regions/all', authenticate, adminController.getFalukantAllRegions);
|
||||
router.post('/falukant/regions', authenticate, adminController.createFalukantRegion);
|
||||
router.delete('/falukant/regions/:id', authenticate, adminController.deleteFalukantRegion);
|
||||
router.put('/falukant/regions/:id/map', authenticate, adminController.updateFalukantRegionMap);
|
||||
router.get('/falukant/region-distances', authenticate, adminController.getRegionDistances);
|
||||
router.post('/falukant/region-distances', authenticate, adminController.upsertRegionDistance);
|
||||
|
||||
@@ -934,6 +934,45 @@ class AdminService {
|
||||
return region;
|
||||
}
|
||||
|
||||
async deleteFalukantRegion(userId, regionId) {
|
||||
if (!(await this.hasUserAccess(userId, 'falukantusers'))) {
|
||||
throw new Error('noaccess');
|
||||
}
|
||||
|
||||
const region = await RegionData.findByPk(regionId);
|
||||
if (!region) {
|
||||
throw new Error('regionNotFound');
|
||||
}
|
||||
|
||||
const [childCount, distanceCount, userCount, characterCount, weatherCount] = await Promise.all([
|
||||
RegionData.count({ where: { parentId: region.id } }),
|
||||
RegionDistance.count({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ sourceRegionId: region.id },
|
||||
{ targetRegionId: region.id },
|
||||
],
|
||||
},
|
||||
}),
|
||||
FalukantUser.count({ where: { mainBranchRegionId: region.id } }),
|
||||
FalukantCharacter.count({ where: { regionId: region.id } }),
|
||||
Weather.count({ where: { regionId: region.id } }),
|
||||
]);
|
||||
|
||||
if (childCount > 0) {
|
||||
throw new Error('regionHasChildren');
|
||||
}
|
||||
if (distanceCount > 0) {
|
||||
throw new Error('regionHasDistances');
|
||||
}
|
||||
if (userCount > 0 || characterCount > 0 || weatherCount > 0) {
|
||||
throw new Error('regionInUse');
|
||||
}
|
||||
|
||||
await region.destroy();
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async getRegionDistances(userId) {
|
||||
if (!(await this.hasUserAccess(userId, 'falukantusers'))) {
|
||||
throw new Error('noaccess');
|
||||
|
||||
Reference in New Issue
Block a user