-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from vocascan/import-export
Import/Export functions
- Loading branch information
Showing
9 changed files
with
408 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
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 | ||
const userId = req.user.id; | ||
|
||
// get language package id from params | ||
const { groupId } = req.params; | ||
|
||
const group = await getAllGroupVocabulary(userId, groupId); | ||
const formatted = { | ||
version: getVersion(), | ||
type: 'vocascan/group', | ||
...group.toJSON(), | ||
}; | ||
res.send(formatted); | ||
}); | ||
|
||
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 queryStatus = (req.query.queryStatus || 'false') === 'true'; | ||
|
||
const languagePackage = await getAllLanguagePackageVocabulary({ userId, languagePackageId, queryStatus }); | ||
const formatted = { | ||
version: getVersion(), | ||
type: 'vocascan/package', | ||
...languagePackage.toJSON(), | ||
}; | ||
|
||
res.send(formatted); | ||
}); | ||
|
||
module.exports = { | ||
exportGroup, | ||
exportLanguagePackage, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const { storeGroupVocabulary, storeLanguagePackageVocabulary } = require('../Services/ImportServiceProvider.js'); | ||
const catchAsync = require('../utils/catchAsync'); | ||
const ApiError = require('../utils/ApiError.js'); | ||
const httpStatus = require('http-status'); | ||
|
||
const importVocabs = 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 { 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'; | ||
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'); | ||
} | ||
|
||
res.status(204).end(); | ||
}); | ||
|
||
module.exports = { | ||
importVocabs, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
const { VocabularyCard, Translation, Group, LanguagePackage, Drawer } = require('../../database'); | ||
|
||
// 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, queryStatus }) { | ||
// Get user with email from database | ||
const languagePackage = await LanguagePackage.findOne({ | ||
// if groups is true, return groups to every language package | ||
include: queryStatus | ||
? [ | ||
{ | ||
model: Group, | ||
attributes: ['name', 'description'], | ||
include: [ | ||
{ | ||
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, | ||
id: languagePackageId, | ||
}, | ||
}); | ||
|
||
return languagePackage; | ||
} | ||
|
||
module.exports = { | ||
getAllGroupVocabulary, | ||
getAllLanguagePackageVocabulary, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
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'); | ||
const { createLanguagePackage } = require('./LanguagePackageServiceProvider.js'); | ||
const { drawers } = require('../utils/constants.js'); | ||
|
||
async function storeGroupVocabulary( | ||
{ name, description, VocabularyCards }, | ||
userId, | ||
languagePackageId, | ||
active, | ||
activate | ||
) { | ||
const languagePackage = await LanguagePackage.findOne({ | ||
where: { | ||
userId, | ||
id: languagePackageId, | ||
}, | ||
}); | ||
|
||
if (!languagePackage) { | ||
throw new ApiError(httpStatus.NOT_FOUND, 'language package not found'); | ||
} | ||
|
||
const transaction = await sequelize.transaction(); | ||
|
||
try { | ||
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) => { | ||
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(); | ||
throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); | ||
} | ||
} | ||
|
||
async function storeLanguagePackageVocabulary( | ||
{ name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords, Groups, Drawers }, | ||
userId, | ||
active, | ||
activate, | ||
queryStatus | ||
) { | ||
if (!Drawers && queryStatus) { | ||
throw new ApiError(httpStatus.BAD_REQUEST, 'No exported drawers found'); | ||
} | ||
|
||
const transaction = await sequelize.transaction(); | ||
|
||
try { | ||
// create language Package | ||
const createdLanguagePackage = await createLanguagePackage( | ||
{ name, foreignWordLanguage, translatedWordLanguage, vocabsPerDay, rightWords }, | ||
userId, | ||
transaction | ||
); | ||
|
||
let getDrawer = () => null; | ||
const yesterday = new Date().setDate(new Date().getDate() - 1); | ||
|
||
// store drawers for language package in database | ||
if (queryStatus) { | ||
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 { | ||
const createdDrawers = await createDrawers(drawers, createdLanguagePackage.id, userId, transaction); | ||
const drawer = createdDrawers.find((_drawer) => +_drawer.stage === (activate ? 1 : 0)); | ||
|
||
getDrawer = () => drawer; | ||
} | ||
|
||
await Promise.all( | ||
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, | ||
drawerId: queryStatus ? getDrawer(vocabularyCard.drawerId).id : getDrawer().id, | ||
name: vocabularyCard.name, | ||
description: vocabularyCard.description, | ||
lastQuery: yesterday, | ||
lastQueryCorrect: yesterday, | ||
active, | ||
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(); | ||
throw new ApiError(httpStatus.BAD_REQUEST, 'Error importing vocabs'); | ||
} | ||
} | ||
|
||
module.exports = { | ||
storeGroupVocabulary, | ||
storeLanguagePackageVocabulary, | ||
}; |
Oops, something went wrong.