const express = require('express') const XL = require('excel4node'); module.exports = function (options) { const db = options.db; var router = express.Router(); router.route('/') .get(function(request, response, next) { db.Project.findAll({ include: [ { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }) .then(projects => { response.display("projects", { user: request.user, pageTitle: "Projects - Mantra", projects: projects }) }) }) router.route('/:id') .get(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.ProjectArtifactVersions, include: [ { association: db.ProjectArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] }, { association: db.Project.ProjectTranslationArtifactVersions, include: [ { association: db.ProjectTranslationArtifactVersion.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] } ] }, { 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(project => { if (project) { response.display("project", { user: request.user, pageTitle: "Projects - Mantra", project: project }) } else { next() } }).catch(error => { next(error) }) }) router.route('/create') .get(function(request, response, next) { response.display("project-form", { user: request.user, pageTitle: "Projects - Mantra", project: { } }) }) .post(function(request, response, next) { db.Project.create({ creatorId: request.user.id, name: request.body.name, description: request.body.description, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] } }, { include: [ { association: db.Project.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }).then(project => { if (project) { response.redirect(`/projects/${project.id}`) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/add-artifact') .get(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.ProjectArtifactVersions }, { association: db.Project.ProjectTranslationArtifactVersions }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { const artifacts = await db.Artifact.findAll({ // Narrow it down to artifacts this user has admin ownership off..., include: [ { association: db.Artifact.ArtifactVersions, limit: 1, required: true // TODO: Order by version... } ] }) response.display("project-add-artifact", { user: request.user, pageTitle: "Projects - Mantra", project: project, artifacts: artifacts }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.ProjectArtifactVersions, where: { artifactVersionId: request.body.artifactVersionId }, required: false, include: [ { association: db.ProjectArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] }, { association: db.Project.ProjectTranslationArtifactVersions, include: [ { association: db.ProjectTranslationArtifactVersion.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] } ] }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { // TODO: check if project.artifactVersions.length == 0 const artifactVersion = await db.ArtifactVersion.findByPk(request.body.artifactVersionId, { // Narrow it down to artifacts this user has admin ownership off..., include: [ { association: db.ArtifactVersion.TranslationArtifactVersions } ] }) if (artifactVersion) { const projectArtifactVersion = await getProjectArtifactVersion(request.user.id, project, artifactVersion) // Bulk create the project translations... const projectTranslationArtifactVersionObjects = artifactVersion.translationArtifactVersions.filter(translationArtifactVersion => { // filter out translations already added to the project... return !project.projectTranslationArtifactVersions.some(projectTranslationArtifactVersions => { return projectTranslationArtifactVersions.translationArtifactVersionId == translationArtifactVersion.id }) }).map(translationArtifactVersion => { return { creatorId: request.user.id, projectId: project.id, translationArtifactVersionId: translationArtifactVersion.id, projectArtifactVersionId: projectArtifactVersion.id } }) if (projectTranslationArtifactVersionObjects.length > 0) { const projectTranslationArtifactVersions = await db.ProjectTranslationArtifactVersion.bulkCreate(projectTranslationArtifactVersionObjects) } response.redirect(`/projects/${project.id}`) } } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/add-translation') .get(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.ProjectArtifactVersions }, { association: db.Project.ProjectTranslationArtifactVersions }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { const translationArtifactVersions = await db.TranslationArtifactVersion.findAll({ // Narrow it down to artifacts this user has admin ownership off..., include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, required: true, // TODO: Order by version... include: [ { association: db.ArtifactVersion.Artifact } ] } ] }) response.display("project-add-translation", { user: request.user, pageTitle: "Projects - Mantra", project: project, translationArtifactVersions: translationArtifactVersions }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.ProjectArtifactVersions }, { association: db.Project.ProjectTranslationArtifactVersions }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { // TODO: Fi const translationArtifactVersion = await db.TranslationArtifactVersion.findByPk(request.body.translationArtifactVersionId, { // Narrow it down to artifacts this user has admin ownership off..., include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, required: true // TODO: Order by version... } ] }) if (translationArtifactVersion) { const projectTranslationArtifactVersion = db.ProjectTranslationArtifactVersion.create({ creatorId: request.user.id, projectId: project.id, translationArtifactVersionId: translationArtifactVersion.id }) response.redirect(`/projects/${project.id}`) } else { response.redirect(`/projects/${project.id}/add-translation`) } } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/campaign') .get(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.Campaign, required: true }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(project => { if (project) { response.redirect(`/campaigns/${project.campaign.id}`) } else { response.redirect(`/projects/${request.params.id}/campaign/create`) } }) }) router.route('/:id/campaign/create') .get(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.Campaign, }, { association: db.Project.ProjectArtifactVersions, include: [ { association: db.ProjectArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] }, { association: db.Project.ProjectTranslationArtifactVersions, include: [ { association: db.ProjectTranslationArtifactVersion.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] } ] }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(project => { if (project) { if (project.campaign) { response.redirect(`/campaigns/${project.campaign.id}`) } else { response.display("campaign-form", { user: request.user, pageTitle: "Campaign - Mantra", campaign: { name: `Campaign for ${project.name} project` }, project: project, }) } } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.Project.findByPk(request.params.id, { include: [ { association: db.Project.Campaign, }, { association: db.Project.ProjectArtifactVersions, include: [ { association: db.ProjectArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] }, { association: db.Project.ProjectTranslationArtifactVersions, include: [ { association: db.ProjectTranslationArtifactVersion.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] } ] } ] }, { association: db.Project.Owner, required: true, include: [ { association: db.Owner.OwnerEntities, required: true, include: [ { association: db.OwnerEntity.Entity, required: true, include: [ { association: db.Entity.EntityUsers, required: true, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { if (project.campaign) { response.redirect(`/campaigns/${project.campaign.id}`) } else { const translationArtifactVersionCampaigns = project.projectTranslationArtifactVersions.map(projectTranslationArtifactVersion => { return { creatorId: request.user.id, translationArtifactVersionId: projectTranslationArtifactVersion.translationArtifactVersionId, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] }, satoshis: request.body.satoshis } }) const campaign = await db.Campaign.create({ creatorId: request.user.id, name: request.body.name, description: request.body.description, // defaultSatoshis: [request.body.satoshis].flat()[0], defaultSatoshis: request.body.satoshis, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] }, translationArtifactVersionCampaigns: translationArtifactVersionCampaigns }, { include: [ { association: db.Campaign.TranslationArtifactVersionCampaigns, include: [ { association: db.TranslationArtifactVersionCampaign.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }, { association: db.Campaign.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }) response.redirect(`/campaigns/${campaign.id}`) } } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/spreadsheet') .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, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { db.TranslationArtifactVersion.findAll({ include: [ // TODO: require translationArtifactVersions in ProjectArtifactVersion { association: db.TranslationArtifactVersion.ProjectTranslationArtifactVersions, required: true, where: { projectId: request.params.id }, }, { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.ProjectArtifactVersions }, { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.TranslationChapters, include: [ { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] } ] } ] }).then(translationArtifactVersions => { const workbook = new XL.Workbook(); const cellWidth = 45 const cellHeight = 25 translationArtifactVersions.forEach((translationArtifactVersion, index) => { const worksheet_name = `${index+1}-${translationArtifactVersion.dialect.countryId}-${translationArtifactVersion.dialect.languageId} - ${translationArtifactVersion.artifactVersion.artifact.name}`.substring(0, 30); // Don't have [ ] * ? : / \ const worksheet = workbook.addWorksheet(worksheet_name.replace(/[`*?:'\[\]\\\/]/gi, "")) worksheet.cell(2,2,2,3,true) .string(translationArtifactVersion.artifactVersion.artifact.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) worksheet.cell(4,2) .string(translationArtifactVersion.artifactVersion.artifact.dialect.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) worksheet.cell(4,3) .string(translationArtifactVersion.dialect.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) // Meta data for the translation and artifact worksheet.cell(4,4) .string(translationArtifactVersion.artifactVersion.id) worksheet.cell(4,5) .string(translationArtifactVersion.id) var cellIndex = 6 const translationChapters = translationArtifactVersion.translationChapters.sort((a, b) => a.index - b.index) for (const i in translationChapters) { const translationChapter = translationChapters[i] const translationChunks = translationChapter.translationChunks.sort((a,b) => a.index - b.index) for (const j in translationChunks) { const translationChunk = translationChunks[j] worksheet.cell(cellIndex,2) .string(translationChunk.text) .style({ alignment: { wrapText: true, vertical: 'justify' } }) const translationCell = worksheet.cell(cellIndex,3) .style({ alignment: { wrapText: true, vertical: 'justify' } }) if (translationChunk.translation) { translationCell.string(translationChunk.translation.text) } const textLength = translationChunk.text.length worksheet.row(cellIndex).setHeight( Math.ceil(Math.max(textLength/cellWidth, 1)*cellHeight) ) // Meta data... // ID for translationChunk worksheet.cell(cellIndex,4) .string(translationChunk.id) // ID for translation worksheet.cell(cellIndex,5) .string(translationChunk.translation?.id ?? "") cellIndex++ } cellIndex++ } // Format Columns worksheet.column(2).setWidth(cellWidth); worksheet.column(3).setWidth(cellWidth); worksheet.column(4).hide(); worksheet.column(5).hide(); // Format Rows... worksheet.row(5).freeze() worksheet.row(1).setHeight(5) worksheet.row(3).setHeight(5) worksheet.row(5).setHeight(5) }) if (translationArtifactVersions.length > 0) { workbook.write(`${project.name}.xlsx`, response); } else { response.redirect(`/projects/${request.params.id}`) } }).catch(error => { next(error) }) } else { next() } }) }) router.route('/:id/sheets') .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, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }).then(async (project) => { if (project) { db.TranslationChapter.findAll({ include: [ { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, required: true, include: [ { association: db.TranslationArtifactVersion.ProjectTranslationArtifactVersions, required: true, where: { projectId: request.params.id }, }, { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.ProjectArtifactVersions }, { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, ] } ] }).then(translationChapters => { const workbook = new XL.Workbook(); const cellWidth = 45 const cellHeight = 25 translationChapters.sort((a, b) => a.index - b.index).forEach((translationChapter, index) => { const worksheet_name = `${index+1}-${translationChapter.translationArtifactVersion.dialect.countryId}-${translationChapter.translationArtifactVersion.dialect.languageId} - ${translationChapter.translationArtifactVersion.artifactVersion.artifact.name}`.substring(0, 30); // Don't have [ ] * ? : / \ const worksheet = workbook.addWorksheet(worksheet_name.replace(/[`*?:'\[\]\\\/]/gi, "")) worksheet.cell(2,2,2,3,true) .string(translationChapter.translationArtifactVersion.artifactVersion.artifact.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) worksheet.cell(4,2) .string(translationChapter.translationArtifactVersion.artifactVersion.artifact.dialect.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) worksheet.cell(4,3) .string(translationChapter.translationArtifactVersion.dialect.name) .style({ font: { bold: true, }, alignment: { horizontal: 'center', wrapText: true } }) // Meta data for the translation and artifact worksheet.cell(4,4) .string(translationChapter.translationArtifactVersion.artifactVersion.id) worksheet.cell(4,5) .string(translationChapter.translationArtifactVersion.id) var cellIndex = 6 const translationChunks = translationChapter.translationChunks.sort((a,b) => a.index - b.index) for (const j in translationChunks) { const translationChunk = translationChunks[j] worksheet.cell(cellIndex,2) .string(translationChunk.text) .style({ alignment: { wrapText: true, vertical: 'justify' } }) const translationCell = worksheet.cell(cellIndex,3) .style({ alignment: { wrapText: true, vertical: 'justify' } }) if (translationChunk.translation) { translationCell.string(translationChunk.translation.text) } const textLength = translationChunk.text.length worksheet.row(cellIndex).setHeight( Math.ceil(Math.max(textLength/cellWidth, 1)*cellHeight) ) // Meta data... // ID for translationChunk worksheet.cell(cellIndex,4) .string(translationChunk.id) // ID for translation worksheet.cell(cellIndex,5) .string(translationChunk.translation?.id ?? "") cellIndex++ } // Format Columns worksheet.column(2).setWidth(cellWidth); worksheet.column(3).setWidth(cellWidth); worksheet.column(4).hide(); worksheet.column(5).hide(); // Format Rows... worksheet.row(5).freeze() worksheet.row(1).setHeight(5) worksheet.row(3).setHeight(5) worksheet.row(5).setHeight(5) }) if (translationChapters.length > 0) { workbook.write(`${project.name}.xlsx`, response); } else { response.redirect(`/projects/${request.params.id}`) } }).catch(error => { next(error) }) } else { next() } }) }) router.route('/:id/tracker') .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) { db.TranslationChapter.findAll({ include: [ { association: db.TranslationChapter.Chapter, }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationChapterTranslators, }, { association: db.TranslationChapter.TranslationChapterProofReaders, }, { association: db.TranslationChapter.TranslationArtifactVersion, required: true, include: [ { association: db.TranslationArtifactVersion.ProjectTranslationArtifactVersions, required: true, where: { projectId: request.params.id }, }, { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.ProjectArtifactVersions }, { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, request.query.dialectId ? { association: db.TranslationArtifactVersion.Dialect, required: true, where: { id: request.query.dialectId } } : { association: db.TranslationArtifactVersion.Dialect, }, request.query.editorId ? { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, required: true, where: { userId: request.query.editorId } } : { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }).then(translationChapters => { response.display("project-tracker", { user: request.user, project: project, translationChapters: translationChapters }) }).catch(error => { next(error) }) } else { next() } }) }) const getProjectArtifactVersion = (userId, project, artifactVersion) => { if (project.projectArtifactVersions.length == 0) { return db.ProjectArtifactVersion.create({ creatorId: userId, projectId: project.id, artifactVersionId: artifactVersion.id }) } else { return project.projectArtifactVersions[0] } } return router; };