Add importing spreadsheet ability
This commit is contained in:
817
package-lock.json
generated
817
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,8 @@
|
|||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"passport": "^0.5.2",
|
"passport": "^0.5.2",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"pug": "^3.0.2"
|
"pug": "^3.0.2",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prompt": "^1.3.0",
|
"prompt": "^1.3.0",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const XL = require('excel4node');
|
const XL = require('excel4node');
|
||||||
|
const XLSX = require("xlsx");
|
||||||
|
|
||||||
module.exports = function (options) {
|
module.exports = function (options) {
|
||||||
const db = options.db;
|
const db = options.db;
|
||||||
@@ -1394,5 +1395,146 @@ module.exports = function (options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.route('/:id/import')
|
||||||
|
.get(function(request, response, next) {
|
||||||
|
db.Project.findByPk(request.params.id, {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Project.Owner,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Owner.OwnerEntities,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.OwnerEntity.Entity,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Entity.EntityUsers,
|
||||||
|
required: false,
|
||||||
|
where: {
|
||||||
|
userId: request.user?.id ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).then(async (project) => {
|
||||||
|
if (project) {
|
||||||
|
response.display("project-translation-importer", {
|
||||||
|
user: request.user,
|
||||||
|
project: project
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
next(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.post(function(request, response, next) {
|
||||||
|
db.Project.findByPk(request.params.id, {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Project.Owner,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Owner.OwnerEntities,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.OwnerEntity.Entity,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.Entity.EntityUsers,
|
||||||
|
required: false, // TODO: Make required...
|
||||||
|
where: {
|
||||||
|
userId: request.user?.id ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).then(async (project) => {
|
||||||
|
if (project && request.files) {
|
||||||
|
const file = request.files.translations
|
||||||
|
|
||||||
|
const workbook = XLSX.read(file.data, {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const sheetName in workbook.Sheets) {
|
||||||
|
const sheet = workbook.Sheets[sheetName];
|
||||||
|
|
||||||
|
const artifactVersionId = sheet["D4"].v
|
||||||
|
const translationArtifactVersionId = sheet["E4"].v
|
||||||
|
|
||||||
|
var lastTranslationChunkId = null
|
||||||
|
var i = 6
|
||||||
|
do {
|
||||||
|
lastTranslationChunkId = null
|
||||||
|
const translationChunkCell = sheet[`D${i}`]
|
||||||
|
if (translationChunkCell) {
|
||||||
|
lastTranslationChunkId = translationChunkCell.v
|
||||||
|
const translatedText = sheet[`C${i}`].v
|
||||||
|
|
||||||
|
if (translatedText) {
|
||||||
|
console.log("Text: ", translatedText)
|
||||||
|
console.log("Chunk Id: ", lastTranslationChunkId)
|
||||||
|
// TODO: Get translationChunk and create translation...
|
||||||
|
const translationChunk = await db.TranslationChunk.findByPk(lastTranslationChunkId, {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
association: db.TranslationChunk.Translation
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (translationChunk) {
|
||||||
|
// Create or update translation
|
||||||
|
if (translationChunk.translation) {
|
||||||
|
// Update translation
|
||||||
|
if (translationChunk.translation.text != translatedText) {
|
||||||
|
translationChunk.translation.text = translatedText
|
||||||
|
// TODO: Update who made the update??
|
||||||
|
await translationChunk.translation.save()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create translation for this chunk
|
||||||
|
const translation = await db.Translation.create({
|
||||||
|
creatorId: request.user.id,
|
||||||
|
translationChunkId: translationChunk.id,
|
||||||
|
text: translatedText,
|
||||||
|
translationArtifactVersionId: translationArtifactVersionId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (lastTranslationChunkId);
|
||||||
|
|
||||||
|
// Chunks...
|
||||||
|
|
||||||
|
console.log("Done processing all...")
|
||||||
|
}
|
||||||
|
|
||||||
|
response.redirect(`/project/${project.id}`)
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
next(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
};
|
};
|
||||||
@@ -29,7 +29,15 @@ block content
|
|||||||
each val, key in query
|
each val, key in query
|
||||||
if key != "sheets"
|
if key != "sheets"
|
||||||
input(type="hidden", name=key, value=val)
|
input(type="hidden", name=key, value=val)
|
||||||
button.btn.black(type="submit") export to spreadsheets
|
button.btn.black(type="submit")
|
||||||
|
i.material-icons.left file_download
|
||||||
|
span export to spreadsheets
|
||||||
|
.row
|
||||||
|
.col.s12
|
||||||
|
a.btn.black(href=`/projects/${project.id}/import`)
|
||||||
|
i.material-icons.left file_upload
|
||||||
|
span import spreadsheets
|
||||||
|
|
||||||
.divider
|
.divider
|
||||||
|
|
||||||
table.highlight
|
table.highlight
|
||||||
|
|||||||
31
server/views/project-translation-importer.pug
Normal file
31
server/views/project-translation-importer.pug
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extend templates/layout.pug
|
||||||
|
|
||||||
|
block content
|
||||||
|
-
|
||||||
|
const isOwnedByUser = project.owner.ownerEntities.some(ownerEntity => {
|
||||||
|
return ownerEntity.entity.entityUsers.some(entityUser => {
|
||||||
|
return entityUser.userId == user?.id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.container
|
||||||
|
.center
|
||||||
|
h1
|
||||||
|
small import
|
||||||
|
span= project.name
|
||||||
|
small translations
|
||||||
|
p.flow-text= project.description
|
||||||
|
|
||||||
|
.row
|
||||||
|
.col.s12
|
||||||
|
form.row(action=`/projects/${project.id}/import`, method="post", encType="multipart/form-data")
|
||||||
|
//- .col.s12.input-field
|
||||||
|
textarea#textarea.materialize-textarea(name="text")
|
||||||
|
label(for="textarea") Entire chapter text (markdown)
|
||||||
|
.file-field.input-field.col.s12
|
||||||
|
.btn
|
||||||
|
span File
|
||||||
|
input#file-input(type="file", name="translations")
|
||||||
|
.file-path-wrapper
|
||||||
|
input.file-path.validate(type="text", placeholder="Import translations")
|
||||||
|
.col.s12
|
||||||
|
button.btn.black(type="submit") import translations
|
||||||
Reference in New Issue
Block a user