From 41889a319047c99bf5aba02c7251375068d8fd60 Mon Sep 17 00:00:00 2001 From: noctera Date: Sat, 10 Jul 2021 10:37:17 +0200 Subject: [PATCH 01/14] chore: export functions --- app/Controllers/ExportController.js | 31 +++++++++++++ app/Services/ExportServiceProvider.js | 64 +++++++++++++++++++++++++++ routes/api.js | 6 +++ 3 files changed, 101 insertions(+) create mode 100644 app/Controllers/ExportController.js create mode 100644 app/Services/ExportServiceProvider.js diff --git a/app/Controllers/ExportController.js b/app/Controllers/ExportController.js new file mode 100644 index 00000000..05c53e1d --- /dev/null +++ b/app/Controllers/ExportController.js @@ -0,0 +1,31 @@ +const { getAllGroupVocabulary, getAllLanguagePackageVocabulary } = require('../Services/ExportServiceProvider.js'); +const catchAsync = require('../utils/catchAsync'); + +const exportGroup = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; + + // get language package id from params + const { groupId } = req.params; + + const group = await getAllGroupVocabulary(userId, groupId); + + res.send(group); +}); + +const exportLanguagePackage = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; + + // get language package id from params + const { languagePackageId } = req.params; + + const languagePackage = await getAllLanguagePackageVocabulary(userId, languagePackageId); + + res.send(languagePackage); +}); + +module.exports = { + exportGroup, + exportLanguagePackage, +}; diff --git a/app/Services/ExportServiceProvider.js b/app/Services/ExportServiceProvider.js new file mode 100644 index 00000000..530f8869 --- /dev/null +++ b/app/Services/ExportServiceProvider.js @@ -0,0 +1,64 @@ +const { VocabularyCard, Translation, Group, LanguagePackage } = require('../../database'); +const ApiError = require('../utils/ApiError.js'); +const httpStatus = require('http-status'); + +// get every vocabulary of a group +async function getAllGroupVocabulary(userId, groupId) { + const group = await Group.findOne({ + attributes: ['name', 'description'], + include: [ + { + model: VocabularyCard, + attributes: ['name', 'description'], + include: [ + { + model: Translation, + attributes: ['name'], + }, + ], + }, + ], + where: { + id: groupId, + userId, + }, + }); + return group; +} + +async function getAllLanguagePackageVocabulary(userId, languagePackageId) { + // Get user with email from database + const languagePackage = await LanguagePackage.findOne({ + // if groups is true, return groups to every language package + include: [ + { + model: Group, + attributes: ['name', 'description'], + include: [ + { + model: VocabularyCard, + attributes: ['name', 'description'], + include: [ + { + model: Translation, + attributes: ['name'], + }, + ], + }, + ], + }, + ], + attributes: ['name', 'foreignWordLanguage', 'translatedWordLanguage', 'vocabsPerDay', 'rightWords'], + where: { + userId, + id: languagePackageId, + }, + }); + + return languagePackage; +} + +module.exports = { + getAllGroupVocabulary, + getAllLanguagePackageVocabulary, +}; diff --git a/routes/api.js b/routes/api.js index a142c1cb..c61c61cc 100644 --- a/routes/api.js +++ b/routes/api.js @@ -13,6 +13,8 @@ const LanguageController = require('../app/Controllers/LanguageController.js'); const DocsController = require('../app/Controllers/DocsController.js'); const StatsController = require('../app/Controllers/StatsController.js'); const InfoController = require('../app/Controllers/InfoController.js'); +const ImportController = require('../app/Controllers/ImportController.js'); +const ExportController = require('../app/Controllers/ExportController.js'); const router = express.Router(); @@ -62,6 +64,10 @@ router.patch('/vocabulary/:vocabularyId', ProtectMiddleware, QueryController.che // Language router.get('/language', ProtectMiddleware, LanguageController.sendLanguages); +// Import / Export +router.get('/export/group/:groupId', ProtectMiddleware, ExportController.exportGroup); +router.get('/export/languagePackage/:languagePackageId', ProtectMiddleware, ExportController.exportLanguagePackage); + // Docs router.get('/swagger.json', DocsController.document); router.use('/swagger', DocsController.swagger); From ceb182cd29532fa936f8cc8a77f0a09de57e40e7 Mon Sep 17 00:00:00 2001 From: noctera Date: Fri, 23 Jul 2021 16:45:45 +0200 Subject: [PATCH 02/14] chore: implementation of package import function --- app/Controllers/ImportController.js | 33 +++++++++ app/Controllers/VocabularyController.js | 12 +++- app/Services/ImportServiceProvider.js | 86 +++++++++++++++++++++++ app/Services/VocabularyServiceProvider.js | 2 +- routes/api.js | 2 + 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 app/Controllers/ImportController.js create mode 100644 app/Services/ImportServiceProvider.js diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js new file mode 100644 index 00000000..b70579d6 --- /dev/null +++ b/app/Controllers/ImportController.js @@ -0,0 +1,33 @@ +const { storeGroupVocabulary, storeLanguagePackageVocabulary } = require('../Services/ImportServiceProvider.js'); +const catchAsync = require('../utils/catchAsync'); + +const importGroup = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; + + // get group with vocabs from request body + const { group, languagePackageId, active, activate } = req.body; + + await storeGroupVocabulary(group, userId, languagePackageId, active, activate); + + res.send('stored'); +}); + +const importLanguagePackage = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; + + // get group with vocabs from request body + const { languagePackage, active, activate } = req.body; + + await storeLanguagePackageVocabulary(languagePackage, userId, active, activate); + + // await storeLanguagePackageVocabulary(group); + + res.send('stored'); +}); + +module.exports = { + importGroup, + importLanguagePackage, +}; diff --git a/app/Controllers/VocabularyController.js b/app/Controllers/VocabularyController.js index 35b4aa44..93f75f92 100644 --- a/app/Controllers/VocabularyController.js +++ b/app/Controllers/VocabularyController.js @@ -11,13 +11,21 @@ const addVocabularyCard = catchAsync(async (req, res) => { // get userId from request const userId = req.user.id; const { name, description, active, translations } = req.body; - const { languagePackageId } = req.params; + const { languagePackageId, groupId } = req.params; // check if user wants to train vocabulary card directly const activate = req.query.activate === 'true'; // create vocabulary card - const vocabularyCard = await createVocabularyCard(req.params, name, description, userId, active, activate); + const vocabularyCard = await createVocabularyCard( + languagePackageId, + groupId, + name, + description, + userId, + active, + activate + ); // parse vocabulary card id from response and create translations await createTranslations(translations, userId, languagePackageId, vocabularyCard.id); diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js new file mode 100644 index 00000000..ce9549d6 --- /dev/null +++ b/app/Services/ImportServiceProvider.js @@ -0,0 +1,86 @@ +const { Group, LanguagePackage } = require('../../database'); +const ApiError = require('../utils/ApiError.js'); +const httpStatus = require('http-status'); +const { createDrawers } = require('./DrawerServiceProvider.js'); +const { createLanguagePackage } = require('./LanguagePackageServiceProvider.js'); +const { drawers } = require('../utils/constants.js'); +const { createVocabularyCard, createTranslations } = require('./VocabularyServiceProvider.js'); + +async function storeGroupVocabulary( + { name, description, VocabularyCards }, + userId, + languagePackageId, + active, + activate +) { + const group = await Group.create({ + userId, + languagePackageId, + name, + description, + active, + }); + + VocabularyCards.forEach(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + languagePackageId, + group.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); + }); +} + +async function storeLanguagePackageVocabulary( + { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords, Groups }, + userId, + active, + activate +) { + // ------------------------------------------// + // TO DO: ADD THESE TWO FUNCTIONS TOGETHER + // ------------------------------------------// + + // create language Package + const createdLanguagePackage = await createLanguagePackage( + { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, + userId + ); + + // store drawers for language package in database + await createDrawers(drawers, createdLanguagePackage.id, userId); + + Groups.forEach(async (group, index) => { + const createdGroup = await Group.create({ + userId, + languagePackageId: createdLanguagePackage.id, + name: group.name, + description: group.description, + active, + }); + + Groups[index].VocabularyCards.forEach(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + createdLanguagePackage.id, + createdGroup.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); + }); + }); +} + +module.exports = { + storeGroupVocabulary, + storeLanguagePackageVocabulary, +}; diff --git a/app/Services/VocabularyServiceProvider.js b/app/Services/VocabularyServiceProvider.js index de614f79..23e4d700 100644 --- a/app/Services/VocabularyServiceProvider.js +++ b/app/Services/VocabularyServiceProvider.js @@ -4,7 +4,7 @@ const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); // create language package -async function createVocabularyCard({ languagePackageId, groupId }, name, description, userId, active, activate) { +async function createVocabularyCard(languagePackageId, groupId, name, description, userId, active, activate) { // if activate = false store vocabulary card in drawer 0 directly // select drawer id depending on the activate state diff --git a/routes/api.js b/routes/api.js index c61c61cc..96b042a9 100644 --- a/routes/api.js +++ b/routes/api.js @@ -67,6 +67,8 @@ router.get('/language', ProtectMiddleware, LanguageController.sendLanguages); // Import / Export router.get('/export/group/:groupId', ProtectMiddleware, ExportController.exportGroup); router.get('/export/languagePackage/:languagePackageId', ProtectMiddleware, ExportController.exportLanguagePackage); +router.post('/import/group/', ProtectMiddleware, ImportController.importGroup); +router.post('/import/languagePackage/', ProtectMiddleware, ImportController.importLanguagePackage); // Docs router.get('/swagger.json', DocsController.document); From f0f73e87e662861bac5670012c83908974174834 Mon Sep 17 00:00:00 2001 From: noctera Date: Mon, 26 Jul 2021 14:37:30 +0200 Subject: [PATCH 03/14] error handling --- app/Services/ExportServiceProvider.js | 2 - app/Services/ImportServiceProvider.js | 111 +++++++++++++++----------- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/app/Services/ExportServiceProvider.js b/app/Services/ExportServiceProvider.js index 530f8869..9f7e2201 100644 --- a/app/Services/ExportServiceProvider.js +++ b/app/Services/ExportServiceProvider.js @@ -1,6 +1,4 @@ const { VocabularyCard, Translation, Group, LanguagePackage } = require('../../database'); -const ApiError = require('../utils/ApiError.js'); -const httpStatus = require('http-status'); // get every vocabulary of a group async function getAllGroupVocabulary(userId, groupId) { diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index ce9549d6..b71fd318 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -1,4 +1,5 @@ -const { Group, LanguagePackage } = require('../../database'); +const { Group } = require('../../database'); +const { ForeignKeyConstraintError } = require('sequelize'); const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); const { createDrawers } = require('./DrawerServiceProvider.js'); @@ -13,27 +14,35 @@ async function storeGroupVocabulary( active, activate ) { - const group = await Group.create({ - userId, - languagePackageId, - name, - description, - active, - }); - - VocabularyCards.forEach(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( - languagePackageId, - group.id, - vocabularyCard.name, - vocabularyCard.description, + try { + const group = await Group.create({ userId, + languagePackageId, + name, + description, active, - activate - ); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); - }); + }); + + VocabularyCards.forEach(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + languagePackageId, + group.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); + }); + } catch (error) { + if (error instanceof ForeignKeyConstraintError) { + throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); + } + + throw error; + } } async function storeLanguagePackageVocabulary( @@ -46,38 +55,46 @@ async function storeLanguagePackageVocabulary( // TO DO: ADD THESE TWO FUNCTIONS TOGETHER // ------------------------------------------// - // create language Package - const createdLanguagePackage = await createLanguagePackage( - { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, - userId - ); + try { + // create language Package + const createdLanguagePackage = await createLanguagePackage( + { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, + userId + ); - // store drawers for language package in database - await createDrawers(drawers, createdLanguagePackage.id, userId); + // store drawers for language package in database + await createDrawers(drawers, createdLanguagePackage.id, userId); - Groups.forEach(async (group, index) => { - const createdGroup = await Group.create({ - userId, - languagePackageId: createdLanguagePackage.id, - name: group.name, - description: group.description, - active, - }); - - Groups[index].VocabularyCards.forEach(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( - createdLanguagePackage.id, - createdGroup.id, - vocabularyCard.name, - vocabularyCard.description, + Groups.forEach(async (group, index) => { + const createdGroup = await Group.create({ userId, + languagePackageId: createdLanguagePackage.id, + name: group.name, + description: group.description, active, - activate - ); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); + }); + + Groups[index].VocabularyCards.forEach(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + createdLanguagePackage.id, + createdGroup.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); + }); }); - }); + } catch (error) { + if (error instanceof ForeignKeyConstraintError) { + throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); + } + + throw error; + } } module.exports = { From 47a9ae3b4e1c310f849b53051038e5b551b41fad Mon Sep 17 00:00:00 2001 From: noctera Date: Thu, 19 Aug 2021 15:14:53 +0200 Subject: [PATCH 04/14] feat: updated params --- app/Controllers/ImportController.js | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js index b70579d6..22080db0 100644 --- a/app/Controllers/ImportController.js +++ b/app/Controllers/ImportController.js @@ -1,33 +1,32 @@ const { storeGroupVocabulary, storeLanguagePackageVocabulary } = require('../Services/ImportServiceProvider.js'); const catchAsync = require('../utils/catchAsync'); -const importGroup = catchAsync(async (req, res) => { - // get userId from request - const userId = req.user.id; +const importGroup = catchAsync(async(req, res) => { + // get userId from request + const userId = req.user.id; - // get group with vocabs from request body - const { group, languagePackageId, active, activate } = req.body; + const { active, activate, languagePackageId } = req.query; - await storeGroupVocabulary(group, userId, languagePackageId, active, activate); + await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); - res.send('stored'); + res.send('stored'); }); -const importLanguagePackage = catchAsync(async (req, res) => { - // get userId from request - const userId = req.user.id; +const importLanguagePackage = catchAsync(async(req, res) => { + // get userId from request + const userId = req.user.id; - // get group with vocabs from request body - const { languagePackage, active, activate } = req.body; + // get group with vocabs from request body + const { active, activate } = req.query; - await storeLanguagePackageVocabulary(languagePackage, userId, active, activate); + await storeLanguagePackageVocabulary(req.body, userId, active, activate); - // await storeLanguagePackageVocabulary(group); + // await storeLanguagePackageVocabulary(group); - res.send('stored'); + res.send('stored'); }); module.exports = { - importGroup, - importLanguagePackage, -}; + importGroup, + importLanguagePackage, +}; \ No newline at end of file From 89e33323652b4bfaa441e9c237e0b35b78825827 Mon Sep 17 00:00:00 2001 From: noctera Date: Thu, 2 Sep 2021 23:31:11 +0200 Subject: [PATCH 05/14] fix: code refactoring --- app/Controllers/ImportController.js | 34 ++++++------- app/Services/ImportServiceProvider.js | 72 +++++++++++++++------------ routes/api.js | 8 +-- 3 files changed, 59 insertions(+), 55 deletions(-) diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js index 22080db0..2532d426 100644 --- a/app/Controllers/ImportController.js +++ b/app/Controllers/ImportController.js @@ -1,32 +1,30 @@ const { storeGroupVocabulary, storeLanguagePackageVocabulary } = require('../Services/ImportServiceProvider.js'); const catchAsync = require('../utils/catchAsync'); -const importGroup = catchAsync(async(req, res) => { - // get userId from request - const userId = req.user.id; +const importGroup = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; - const { active, activate, languagePackageId } = req.query; + const { active, activate, languagePackageId } = req.query; - await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); + await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); - res.send('stored'); + res.status(204).end(); }); -const importLanguagePackage = catchAsync(async(req, res) => { - // get userId from request - const userId = req.user.id; +const importLanguagePackage = catchAsync(async (req, res) => { + // get userId from request + const userId = req.user.id; - // get group with vocabs from request body - const { active, activate } = req.query; + // get group with vocabs from request body + const { active, activate } = req.query; - await storeLanguagePackageVocabulary(req.body, userId, active, activate); + await storeLanguagePackageVocabulary(req.body, userId, active, activate); - // await storeLanguagePackageVocabulary(group); - - res.send('stored'); + res.status(204).end(); }); module.exports = { - importGroup, - importLanguagePackage, -}; \ No newline at end of file + importGroup, + importLanguagePackage, +}; diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index b71fd318..acb9e319 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -23,19 +23,21 @@ async function storeGroupVocabulary( active, }); - VocabularyCards.forEach(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( - languagePackageId, - group.id, - vocabularyCard.name, - vocabularyCard.description, - userId, - active, - activate - ); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); - }); + await Promise.all( + VocabularyCards.map(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + languagePackageId, + group.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); + }) + ); } catch (error) { if (error instanceof ForeignKeyConstraintError) { throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); @@ -65,29 +67,33 @@ async function storeLanguagePackageVocabulary( // store drawers for language package in database await createDrawers(drawers, createdLanguagePackage.id, userId); - Groups.forEach(async (group, index) => { - const createdGroup = await Group.create({ - userId, - languagePackageId: createdLanguagePackage.id, - name: group.name, - description: group.description, - active, - }); - - Groups[index].VocabularyCards.forEach(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( - createdLanguagePackage.id, - createdGroup.id, - vocabularyCard.name, - vocabularyCard.description, + await Promise.all( + Groups.map(async (group, index) => { + const createdGroup = await Group.create({ userId, + languagePackageId: createdLanguagePackage.id, + name: group.name, + description: group.description, active, - activate + }); + + await Promise.all( + Groups[index].VocabularyCards.map(async (vocabularyCard) => { + const createdCard = await createVocabularyCard( + createdLanguagePackage.id, + createdGroup.id, + vocabularyCard.name, + vocabularyCard.description, + userId, + active, + activate + ); + // parse vocabulary card id from response and create translations + createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); + }) ); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); - }); - }); + }) + ); } catch (error) { if (error instanceof ForeignKeyConstraintError) { throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); diff --git a/routes/api.js b/routes/api.js index 96b042a9..c171c9e9 100644 --- a/routes/api.js +++ b/routes/api.js @@ -65,10 +65,10 @@ router.patch('/vocabulary/:vocabularyId', ProtectMiddleware, QueryController.che router.get('/language', ProtectMiddleware, LanguageController.sendLanguages); // Import / Export -router.get('/export/group/:groupId', ProtectMiddleware, ExportController.exportGroup); -router.get('/export/languagePackage/:languagePackageId', ProtectMiddleware, ExportController.exportLanguagePackage); -router.post('/import/group/', ProtectMiddleware, ImportController.importGroup); -router.post('/import/languagePackage/', ProtectMiddleware, ImportController.importLanguagePackage); +router.get('/group/:groupId/export', ProtectMiddleware, ExportController.exportGroup); +router.get('/languagePackage/:languagePackageId/export', ProtectMiddleware, ExportController.exportLanguagePackage); +router.post('/group/import', ProtectMiddleware, ImportController.importGroup); +router.post('/languagePackage/import', ProtectMiddleware, ImportController.importLanguagePackage); // Docs router.get('/swagger.json', DocsController.document); From 833f57964e2167a5ff03fd8cf85769ccbc889ec7 Mon Sep 17 00:00:00 2001 From: noctera Date: Thu, 2 Sep 2021 23:48:34 +0200 Subject: [PATCH 06/14] fix: destructuring for parameters --- app/Controllers/VocabularyController.js | 6 +++--- app/Services/ImportServiceProvider.js | 12 ++++++------ app/Services/VocabularyServiceProvider.js | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/Controllers/VocabularyController.js b/app/Controllers/VocabularyController.js index 93f75f92..51775852 100644 --- a/app/Controllers/VocabularyController.js +++ b/app/Controllers/VocabularyController.js @@ -17,15 +17,15 @@ const addVocabularyCard = catchAsync(async (req, res) => { const activate = req.query.activate === 'true'; // create vocabulary card - const vocabularyCard = await createVocabularyCard( + const vocabularyCard = await createVocabularyCard({ languagePackageId, groupId, name, description, userId, active, - activate - ); + activate, + }); // parse vocabulary card id from response and create translations await createTranslations(translations, userId, languagePackageId, vocabularyCard.id); diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index acb9e319..f2c484d7 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -25,15 +25,15 @@ async function storeGroupVocabulary( await Promise.all( VocabularyCards.map(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( + const createdCard = await createVocabularyCard({ languagePackageId, - group.id, - vocabularyCard.name, - vocabularyCard.description, + groupId: group.id, + name: vocabularyCard.name, + description: vocabularyCard.description, userId, active, - activate - ); + activate, + }); // parse vocabulary card id from response and create translations createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); }) diff --git a/app/Services/VocabularyServiceProvider.js b/app/Services/VocabularyServiceProvider.js index 23e4d700..a8e7816a 100644 --- a/app/Services/VocabularyServiceProvider.js +++ b/app/Services/VocabularyServiceProvider.js @@ -4,7 +4,7 @@ const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); // create language package -async function createVocabularyCard(languagePackageId, groupId, name, description, userId, active, activate) { +async function createVocabularyCard({ languagePackageId, groupId, name, description, userId, active, activate }) { // if activate = false store vocabulary card in drawer 0 directly // select drawer id depending on the activate state From e4e7e7580460c6dd3d741f809605095d2bececa6 Mon Sep 17 00:00:00 2001 From: noctera Date: Wed, 8 Sep 2021 23:59:51 +0200 Subject: [PATCH 07/14] feat: ability to import and export query status --- app/Controllers/ExportController.js | 3 +- app/Controllers/ImportController.js | 11 ++++-- app/Services/DrawerServiceProvider.js | 5 ++- app/Services/ExportServiceProvider.js | 47 +++++++++++++++++------ app/Services/ImportServiceProvider.js | 37 +++++++++++++----- app/Services/VocabularyServiceProvider.js | 34 +++++++++++----- 6 files changed, 99 insertions(+), 38 deletions(-) diff --git a/app/Controllers/ExportController.js b/app/Controllers/ExportController.js index 05c53e1d..0b1deb48 100644 --- a/app/Controllers/ExportController.js +++ b/app/Controllers/ExportController.js @@ -19,8 +19,9 @@ const exportLanguagePackage = catchAsync(async (req, res) => { // get language package id from params const { languagePackageId } = req.params; + const queryStatus = (req.query.queryStatus || 'false') === 'true'; - const languagePackage = await getAllLanguagePackageVocabulary(userId, languagePackageId); + const languagePackage = await getAllLanguagePackageVocabulary({ userId, languagePackageId, queryStatus }); res.send(languagePackage); }); diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js index 2532d426..48fadbe1 100644 --- a/app/Controllers/ImportController.js +++ b/app/Controllers/ImportController.js @@ -5,7 +5,9 @@ const importGroup = catchAsync(async (req, res) => { // get userId from request const userId = req.user.id; - const { active, activate, languagePackageId } = req.query; + const active = (req.query.active || 'true') === 'true'; + const activate = (req.query.activate || 'false') === 'true'; + const { languagePackageId } = req.query; await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); @@ -16,10 +18,11 @@ const importLanguagePackage = catchAsync(async (req, res) => { // get userId from request const userId = req.user.id; - // get group with vocabs from request body - const { active, activate } = req.query; + const active = (req.query.active || 'true') === 'true'; + const activate = (req.query.activate || 'false') === 'true'; + const queryStatus = (req.query.queryStatus || 'false') === 'true'; - await storeLanguagePackageVocabulary(req.body, userId, active, activate); + await storeLanguagePackageVocabulary(req.body, userId, active, activate, queryStatus); res.status(204).end(); }); diff --git a/app/Services/DrawerServiceProvider.js b/app/Services/DrawerServiceProvider.js index 1a85b1ee..dfd25eda 100644 --- a/app/Services/DrawerServiceProvider.js +++ b/app/Services/DrawerServiceProvider.js @@ -13,11 +13,14 @@ async function createDrawer(languagePackageId, stage, queryInterval, userId) { } async function createDrawers(drawers, languagePackageId, userId) { + const allDrawers = []; await Promise.all( drawers.map(async (drawer) => { - await createDrawer(languagePackageId, drawer.stage, drawer.queryInterval, userId); + allDrawers.push(await createDrawer(languagePackageId, drawer.stage, drawer.queryInterval, userId)); }) ); + + return allDrawers; } module.exports = { diff --git a/app/Services/ExportServiceProvider.js b/app/Services/ExportServiceProvider.js index 9f7e2201..d2455564 100644 --- a/app/Services/ExportServiceProvider.js +++ b/app/Services/ExportServiceProvider.js @@ -1,4 +1,4 @@ -const { VocabularyCard, Translation, Group, LanguagePackage } = require('../../database'); +const { VocabularyCard, Translation, Group, LanguagePackage, Drawer } = require('../../database'); // get every vocabulary of a group async function getAllGroupVocabulary(userId, groupId) { @@ -24,28 +24,51 @@ async function getAllGroupVocabulary(userId, groupId) { return group; } -async function getAllLanguagePackageVocabulary(userId, languagePackageId) { +async function getAllLanguagePackageVocabulary({ userId, languagePackageId, queryStatus }) { // Get user with email from database const languagePackage = await LanguagePackage.findOne({ // if groups is true, return groups to every language package - include: [ - { - model: Group, - attributes: ['name', 'description'], - include: [ + include: queryStatus + ? [ { - model: VocabularyCard, + model: Group, attributes: ['name', 'description'], include: [ { - model: Translation, - attributes: ['name'], + model: VocabularyCard, + attributes: queryStatus ? ['name', 'description', 'drawerId'] : ['name', 'description'], + include: [ + { + model: Translation, + attributes: ['name'], + }, + ], + }, + ], + }, + { + model: Drawer, + attributes: ['id', 'stage', 'queryInterval'], + }, + ] + : [ + { + model: Group, + attributes: ['name', 'description'], + include: [ + { + model: VocabularyCard, + attributes: queryStatus ? ['name', 'description', 'drawerId'] : ['name', 'description'], + include: [ + { + model: Translation, + attributes: ['name'], + }, + ], }, ], }, ], - }, - ], attributes: ['name', 'foreignWordLanguage', 'translatedWordLanguage', 'vocabsPerDay', 'rightWords'], where: { userId, diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index f2c484d7..6374f580 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -48,24 +48,34 @@ async function storeGroupVocabulary( } async function storeLanguagePackageVocabulary( - { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords, Groups }, + { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords, Groups, Drawers }, userId, active, - activate + activate, + queryStatus ) { // ------------------------------------------// // TO DO: ADD THESE TWO FUNCTIONS TOGETHER // ------------------------------------------// try { + if (!Drawers && queryStatus) { + throw new ApiError(httpStatus.BAD_REQUEST, 'No exported drawers found'); + } // create language Package const createdLanguagePackage = await createLanguagePackage( { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, userId ); + let createdDrawers = []; + + if (queryStatus) { + createdDrawers = await createDrawers(Drawers, createdLanguagePackage.id, userId); + } else { + createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId); + } // store drawers for language package in database - await createDrawers(drawers, createdLanguagePackage.id, userId); await Promise.all( Groups.map(async (group, index) => { @@ -79,15 +89,22 @@ async function storeLanguagePackageVocabulary( await Promise.all( Groups[index].VocabularyCards.map(async (vocabularyCard) => { - const createdCard = await createVocabularyCard( - createdLanguagePackage.id, - createdGroup.id, - vocabularyCard.name, - vocabularyCard.description, + const createdCard = await createVocabularyCard({ + languagePackageId: createdLanguagePackage.id, + groupId: createdGroup.id, + name: vocabularyCard.name, + description: vocabularyCard.description, + // when drawers are imported too, put new vocabs in imported stages + + drawerId: queryStatus + ? createdDrawers.find( + (drawer) => drawer.stage === Drawers.find((element) => element.id === vocabularyCard.drawerId).stage + ).id + : null, userId, active, - activate - ); + activate, + }); // parse vocabulary card id from response and create translations createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); }) diff --git a/app/Services/VocabularyServiceProvider.js b/app/Services/VocabularyServiceProvider.js index a8e7816a..2f1fbed6 100644 --- a/app/Services/VocabularyServiceProvider.js +++ b/app/Services/VocabularyServiceProvider.js @@ -4,18 +4,32 @@ const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); // create language package -async function createVocabularyCard({ languagePackageId, groupId, name, description, userId, active, activate }) { +async function createVocabularyCard({ + languagePackageId, + groupId, + name, + description, + userId, + active, + activate, + drawerId, +}) { // if activate = false store vocabulary card in drawer 0 directly - // select drawer id depending on the activate state - const drawer = await Drawer.findOne({ - attributes: ['id'], - where: { - stage: activate ? 1 : 0, - languagePackageId, - userId, - }, - }); + // select drawer id depending on the activate and drawerId state + let drawer = {}; + if (drawerId) { + drawer.id = drawerId; + } else { + drawer = await Drawer.findOne({ + attributes: ['id'], + where: { + stage: activate ? 1 : 0, + languagePackageId, + userId, + }, + }); + } if (!drawer) { throw new ApiError(httpStatus.NOT_FOUND, 'no drawer found due to wrong language package id'); From 4a1d3a77ac08a1ec4d125b0654aa065a6b073745 Mon Sep 17 00:00:00 2001 From: noctera Date: Thu, 9 Sep 2021 00:27:09 +0200 Subject: [PATCH 08/14] chore: handle missing drawerId property --- app/Services/ImportServiceProvider.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index 6374f580..c9e0e25e 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -97,8 +97,11 @@ async function storeLanguagePackageVocabulary( // when drawers are imported too, put new vocabs in imported stages drawerId: queryStatus - ? createdDrawers.find( - (drawer) => drawer.stage === Drawers.find((element) => element.id === vocabularyCard.drawerId).stage + ? ( + createdDrawers.find( + (drawer) => + drawer.stage === (Drawers.find((element) => element.id === vocabularyCard.drawerId) || {}).stage + ) || {} ).id : null, userId, From d0a8372f35f5e930e724651227d264cc090baa52 Mon Sep 17 00:00:00 2001 From: luwol03 Date: Thu, 9 Sep 2021 19:36:36 +0200 Subject: [PATCH 09/14] proposal: improved import handeling --- app/Services/DrawerServiceProvider.js | 17 +- app/Services/ImportServiceProvider.js | 173 ++++++++++++------ .../LanguagePackageServiceProvider.js | 22 ++- 3 files changed, 137 insertions(+), 75 deletions(-) diff --git a/app/Services/DrawerServiceProvider.js b/app/Services/DrawerServiceProvider.js index dfd25eda..a4b08773 100644 --- a/app/Services/DrawerServiceProvider.js +++ b/app/Services/DrawerServiceProvider.js @@ -12,15 +12,18 @@ async function createDrawer(languagePackageId, stage, queryInterval, userId) { return drawer; } -async function createDrawers(drawers, languagePackageId, userId) { - const allDrawers = []; - await Promise.all( - drawers.map(async (drawer) => { - allDrawers.push(await createDrawer(languagePackageId, drawer.stage, drawer.queryInterval, userId)); - }) +async function createDrawers(drawers, languagePackageId, userId, transaction) { + const createdDrawers = await Drawer.bulkCreate( + drawers.map((drawer) => ({ + userId, + languagePackageId, + stage: drawer.stage, + queryInterval: drawer.queryInterval, + })), + { transaction } ); - return allDrawers; + return createdDrawers; } module.exports = { diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index c9e0e25e..c7d2210b 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -1,11 +1,10 @@ -const { Group } = require('../../database'); +const { Group, VocabularyCard, Translation, Drawer, sequelize } = require('../../database'); const { ForeignKeyConstraintError } = require('sequelize'); const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); const { createDrawers } = require('./DrawerServiceProvider.js'); const { createLanguagePackage } = require('./LanguagePackageServiceProvider.js'); const { drawers } = require('../utils/constants.js'); -const { createVocabularyCard, createTranslations } = require('./VocabularyServiceProvider.js'); async function storeGroupVocabulary( { name, description, VocabularyCards }, @@ -14,31 +13,66 @@ async function storeGroupVocabulary( active, activate ) { + const transaction = await sequelize.transaction(); + try { - const group = await Group.create({ - userId, - languagePackageId, - name, - description, - active, + const group = await Group.create( + { + userId, + languagePackageId, + name, + description, + active, + }, + { transaction } + ); + + const drawer = await Drawer.findOne({ + where: { + userId, + languagePackageId, + stage: activate ? 1 : 0, + }, + transaction, }); + const yesterday = new Date().setDate(new Date().getDate() - 1); + await Promise.all( VocabularyCards.map(async (vocabularyCard) => { - const createdCard = await createVocabularyCard({ - languagePackageId, - groupId: group.id, - name: vocabularyCard.name, - description: vocabularyCard.description, - userId, - active, - activate, - }); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, languagePackageId, createdCard.id); + await VocabularyCard.create( + { + userId, + languagePackageId, + groupId: group.id, + drawerId: drawer.id, + name: vocabularyCard.name, + description: vocabularyCard.description, + lastQuery: yesterday, + lastQueryCorrect: yesterday, + active, + Translations: vocabularyCard.Translations.map((translation) => ({ + name: translation.name, + userId, + languagePackageId, + })), + }, + { + transaction, + include: [ + { + model: Translation, + }, + ], + } + ); }) ); + + await transaction.commit(); } catch (error) { + await transaction.rollback(); + if (error instanceof ForeignKeyConstraintError) { throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); } @@ -54,67 +88,88 @@ async function storeLanguagePackageVocabulary( activate, queryStatus ) { - // ------------------------------------------// - // TO DO: ADD THESE TWO FUNCTIONS TOGETHER - // ------------------------------------------// + if (!Drawers && queryStatus) { + throw new ApiError(httpStatus.BAD_REQUEST, 'No exported drawers found'); + } + + const transaction = await sequelize.transaction(); try { - if (!Drawers && queryStatus) { - throw new ApiError(httpStatus.BAD_REQUEST, 'No exported drawers found'); - } // create language Package const createdLanguagePackage = await createLanguagePackage( { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, - userId + userId, + transaction ); - let createdDrawers = []; + let getDrawer = () => null; + const yesterday = new Date().setDate(new Date().getDate() - 1); + // store drawers for language package in database if (queryStatus) { - createdDrawers = await createDrawers(Drawers, createdLanguagePackage.id, userId); + const createdDrawers = await createDrawers(Drawers, createdLanguagePackage.id, userId, transaction); + const drawerMap = Drawers.reduce( + (_drawerMap, oldDrawer, index) => ({ + ..._drawerMap, + [oldDrawer.id]: createdDrawers[index], + }), + {} + ); + + getDrawer = (oldId) => drawerMap[oldId]; } else { - createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId); + const createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId, transaction); + const drawer = createdDrawers.find((_drawer) => _drawer.stage === (activate ? '1' : '0')); + + getDrawer = () => drawer; } - // store drawers for language package in database await Promise.all( - Groups.map(async (group, index) => { - const createdGroup = await Group.create({ - userId, - languagePackageId: createdLanguagePackage.id, - name: group.name, - description: group.description, - active, - }); - - await Promise.all( - Groups[index].VocabularyCards.map(async (vocabularyCard) => { - const createdCard = await createVocabularyCard({ + Groups.map(async (group) => { + await Group.create( + { + userId, + languagePackageId: createdLanguagePackage.id, + name: group.name, + description: group.description, + active, + VocabularyCards: group.VocabularyCards.map((vocabularyCard) => ({ + userId, languagePackageId: createdLanguagePackage.id, - groupId: createdGroup.id, + drawerId: queryStatus ? getDrawer(vocabularyCard.drawerId).id : getDrawer().id, name: vocabularyCard.name, description: vocabularyCard.description, - // when drawers are imported too, put new vocabs in imported stages - - drawerId: queryStatus - ? ( - createdDrawers.find( - (drawer) => - drawer.stage === (Drawers.find((element) => element.id === vocabularyCard.drawerId) || {}).stage - ) || {} - ).id - : null, - userId, + lastQuery: yesterday, + lastQueryCorrect: yesterday, active, - activate, - }); - // parse vocabulary card id from response and create translations - createTranslations(vocabularyCard.Translations, userId, createdLanguagePackage.id, createdCard.id); - }) + Translations: vocabularyCard.Translations.map((translation) => ({ + name: translation.name, + userId, + languagePackageId: createdLanguagePackage.id, + })), + })), + }, + { + transaction, + include: [ + { + model: VocabularyCard, + include: [ + { + model: Translation, + }, + ], + }, + ], + } ); }) ); + + await transaction.commit(); } catch (error) { + await transaction.rollback(); + if (error instanceof ForeignKeyConstraintError) { throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); } diff --git a/app/Services/LanguagePackageServiceProvider.js b/app/Services/LanguagePackageServiceProvider.js index 7aef2d2a..8dc9663c 100644 --- a/app/Services/LanguagePackageServiceProvider.js +++ b/app/Services/LanguagePackageServiceProvider.js @@ -7,17 +7,21 @@ const httpStatus = require('http-status'); // create language package async function createLanguagePackage( { name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, - userId + userId, + transaction ) { try { - const languagePackage = await LanguagePackage.create({ - userId, - name, - foreignWordLanguage, - translatedWordLanguage, - vocabsPerDay, - rightWords, - }); + const languagePackage = await LanguagePackage.create( + { + userId, + name, + foreignWordLanguage, + translatedWordLanguage, + vocabsPerDay, + rightWords, + }, + { transaction } + ); return deleteKeysFromObject(['userId', 'createdAt', 'updatedAt'], languagePackage.toJSON()); } catch (error) { From 58da2dd937d597ae1bf365bb6318fd4726edc8e0 Mon Sep 17 00:00:00 2001 From: noctera Date: Fri, 17 Sep 2021 12:44:50 +0200 Subject: [PATCH 10/14] fix: string and int comparison --- app/Services/ImportServiceProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index c7d2210b..93b6cfb3 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -119,7 +119,7 @@ async function storeLanguagePackageVocabulary( getDrawer = (oldId) => drawerMap[oldId]; } else { const createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId, transaction); - const drawer = createdDrawers.find((_drawer) => _drawer.stage === (activate ? '1' : '0')); + const drawer = createdDrawers.find((_drawer) => _drawer.stage === (activate ? 1 : 0)); getDrawer = () => drawer; } From 715b5ac6ffff9c137b7ed95441883e24689d910d Mon Sep 17 00:00:00 2001 From: noctera Date: Fri, 24 Sep 2021 23:00:09 +0200 Subject: [PATCH 11/14] refactor: added type properties for easier import --- app/Controllers/ExportController.js | 16 +++++++++++--- app/Controllers/ImportController.js | 32 +++++++++++++-------------- app/Services/ImportServiceProvider.js | 16 +++----------- routes/api.js | 3 +-- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/app/Controllers/ExportController.js b/app/Controllers/ExportController.js index 0b1deb48..466f4bcf 100644 --- a/app/Controllers/ExportController.js +++ b/app/Controllers/ExportController.js @@ -1,5 +1,6 @@ const { getAllGroupVocabulary, getAllLanguagePackageVocabulary } = require('../Services/ExportServiceProvider.js'); const catchAsync = require('../utils/catchAsync'); +const { getVersion } = require('../Services/InfoServiceProvider'); const exportGroup = catchAsync(async (req, res) => { // get userId from request @@ -9,8 +10,12 @@ const exportGroup = catchAsync(async (req, res) => { const { groupId } = req.params; const group = await getAllGroupVocabulary(userId, groupId); - - res.send(group); + const formatted = { + version: getVersion(), + type: 'vocascan/group', + ...group.toJSON(), + }; + res.send(formatted); }); const exportLanguagePackage = catchAsync(async (req, res) => { @@ -22,8 +27,13 @@ const exportLanguagePackage = catchAsync(async (req, res) => { const queryStatus = (req.query.queryStatus || 'false') === 'true'; const languagePackage = await getAllLanguagePackageVocabulary({ userId, languagePackageId, queryStatus }); + const formatted = { + version: getVersion(), + type: 'vocascan/package', + ...languagePackage.toJSON(), + }; - res.send(languagePackage); + res.send(formatted); }); module.exports = { diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js index 48fadbe1..0629bafd 100644 --- a/app/Controllers/ImportController.js +++ b/app/Controllers/ImportController.js @@ -1,7 +1,9 @@ const { storeGroupVocabulary, storeLanguagePackageVocabulary } = require('../Services/ImportServiceProvider.js'); const catchAsync = require('../utils/catchAsync'); +const ApiError = require('../utils/ApiError.js'); +const httpStatus = require('http-status'); -const importGroup = catchAsync(async (req, res) => { +const importVocabs = catchAsync(async (req, res) => { // get userId from request const userId = req.user.id; @@ -9,25 +11,23 @@ const importGroup = catchAsync(async (req, res) => { const activate = (req.query.activate || 'false') === 'true'; const { languagePackageId } = req.query; - await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); + const { type } = req.body; + // use different types of import to separate the functions + if (!type) { + throw new ApiError(httpStatus.BAD_REQUEST, 'imported data has no Vocascan structure'); + } else if (type === 'vocascan/package') { + const queryStatus = (req.query.queryStatus || 'false') === 'true'; - res.status(204).end(); -}); - -const importLanguagePackage = catchAsync(async (req, res) => { - // get userId from request - const userId = req.user.id; - - const active = (req.query.active || 'true') === 'true'; - const activate = (req.query.activate || 'false') === 'true'; - const queryStatus = (req.query.queryStatus || 'false') === 'true'; - - await storeLanguagePackageVocabulary(req.body, userId, active, activate, queryStatus); + await storeLanguagePackageVocabulary(req.body, userId, active, activate, queryStatus); + } else if (type === 'vocascan/group') { + await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); + } else { + throw new ApiError(httpStatus.BAD_REQUEST, 'imported data type not recognized'); + } res.status(204).end(); }); module.exports = { - importGroup, - importLanguagePackage, + importVocabs, }; diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index 93b6cfb3..a983958d 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -72,12 +72,7 @@ async function storeGroupVocabulary( await transaction.commit(); } catch (error) { await transaction.rollback(); - - if (error instanceof ForeignKeyConstraintError) { - throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); - } - - throw error; + throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); } } @@ -119,7 +114,7 @@ async function storeLanguagePackageVocabulary( getDrawer = (oldId) => drawerMap[oldId]; } else { const createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId, transaction); - const drawer = createdDrawers.find((_drawer) => _drawer.stage === (activate ? 1 : 0)); + const drawer = createdDrawers.find((_drawer) => +_drawer.stage === (activate ? 1 : 0)); getDrawer = () => drawer; } @@ -169,12 +164,7 @@ async function storeLanguagePackageVocabulary( await transaction.commit(); } catch (error) { await transaction.rollback(); - - if (error instanceof ForeignKeyConstraintError) { - throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); - } - - throw error; + throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); } } diff --git a/routes/api.js b/routes/api.js index c171c9e9..9186458e 100644 --- a/routes/api.js +++ b/routes/api.js @@ -67,8 +67,7 @@ router.get('/language', ProtectMiddleware, LanguageController.sendLanguages); // Import / Export router.get('/group/:groupId/export', ProtectMiddleware, ExportController.exportGroup); router.get('/languagePackage/:languagePackageId/export', ProtectMiddleware, ExportController.exportLanguagePackage); -router.post('/group/import', ProtectMiddleware, ImportController.importGroup); -router.post('/languagePackage/import', ProtectMiddleware, ImportController.importLanguagePackage); +router.post('/import', ProtectMiddleware, ImportController.importVocabs); // Docs router.get('/swagger.json', DocsController.document); From 077cf6106b2da26ec100db02cd57b1cfd709dcb0 Mon Sep 17 00:00:00 2001 From: noctera Date: Fri, 24 Sep 2021 23:11:37 +0200 Subject: [PATCH 12/14] style: fix linting issues --- app/Controllers/ImportController.js | 3 +-- app/Services/ImportServiceProvider.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/Controllers/ImportController.js b/app/Controllers/ImportController.js index 0629bafd..8a8c1367 100644 --- a/app/Controllers/ImportController.js +++ b/app/Controllers/ImportController.js @@ -9,7 +9,6 @@ const importVocabs = catchAsync(async (req, res) => { const active = (req.query.active || 'true') === 'true'; const activate = (req.query.activate || 'false') === 'true'; - const { languagePackageId } = req.query; const { type } = req.body; // use different types of import to separate the functions @@ -17,9 +16,9 @@ const importVocabs = catchAsync(async (req, res) => { throw new ApiError(httpStatus.BAD_REQUEST, 'imported data has no Vocascan structure'); } else if (type === 'vocascan/package') { const queryStatus = (req.query.queryStatus || 'false') === 'true'; - await storeLanguagePackageVocabulary(req.body, userId, active, activate, queryStatus); } else if (type === 'vocascan/group') { + const { languagePackageId } = req.query; await storeGroupVocabulary(req.body, userId, languagePackageId, active, activate); } else { throw new ApiError(httpStatus.BAD_REQUEST, 'imported data type not recognized'); diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index a983958d..cc43041a 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -1,5 +1,4 @@ const { Group, VocabularyCard, Translation, Drawer, sequelize } = require('../../database'); -const { ForeignKeyConstraintError } = require('sequelize'); const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); const { createDrawers } = require('./DrawerServiceProvider.js'); From 72ebd8b626f8fbb00f2eac428522a9318494b402 Mon Sep 17 00:00:00 2001 From: noctera Date: Sat, 9 Oct 2021 00:06:10 +0200 Subject: [PATCH 13/14] fix: error handling when package missing --- app/Services/ImportServiceProvider.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index cc43041a..f3af5f7e 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -1,4 +1,4 @@ -const { Group, VocabularyCard, Translation, Drawer, sequelize } = require('../../database'); +const { Group, LanguagePackage, VocabularyCard, Translation, Drawer, sequelize } = require('../../database'); const ApiError = require('../utils/ApiError.js'); const httpStatus = require('http-status'); const { createDrawers } = require('./DrawerServiceProvider.js'); @@ -14,6 +14,17 @@ async function storeGroupVocabulary( ) { const transaction = await sequelize.transaction(); + const languagePackage = await LanguagePackage.findOne({ + where: { + userId, + id: languagePackageId, + }, + }); + + if (!languagePackage) { + throw new ApiError(httpStatus.NOT_FOUND, 'language package not found'); + } + try { const group = await Group.create( { From da25c894ca9a1eb869230052cc21e697d326da21 Mon Sep 17 00:00:00 2001 From: noctera Date: Sun, 10 Oct 2021 10:49:14 +0200 Subject: [PATCH 14/14] refactor: moved transaction downwards --- app/Services/ImportServiceProvider.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Services/ImportServiceProvider.js b/app/Services/ImportServiceProvider.js index f3af5f7e..0849c6af 100644 --- a/app/Services/ImportServiceProvider.js +++ b/app/Services/ImportServiceProvider.js @@ -12,8 +12,6 @@ async function storeGroupVocabulary( active, activate ) { - const transaction = await sequelize.transaction(); - const languagePackage = await LanguagePackage.findOne({ where: { userId, @@ -25,6 +23,8 @@ async function storeGroupVocabulary( throw new ApiError(httpStatus.NOT_FOUND, 'language package not found'); } + const transaction = await sequelize.transaction(); + try { const group = await Group.create( {