const express = require('express') const { Op } = require("sequelize") const idGenerator = require('mantra-db-models/src/lib/id-generator'); const markdownProducer = require("../../../lib/markdown-producer") module.exports = function (options) { const db = options.db; var router = express.Router(); router.route('/:id') .get(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Owner, // required: false, include: [ { association: db.Owner.OwnerEntities, // required: true, include: [ { association: db.OwnerEntity.Entity, // required: false, include: [ { association: db.Entity.EntityUsers, required: false, where: { userId: request.user?.id ?? null } } ] } ] } ] } ] }, { association: db.ArtifactVersion.Chapters } ] }, { association: db.TranslationArtifactVersion.ForkedFrom }, { association: db.TranslationArtifactVersion.TranslationChapters, include: [ { association: db.TranslationChapter.Chapter } ] }, { association: db.TranslationArtifactVersion.Owner, // required: false, include: [ { association: db.Owner.OwnerEntities, // required: true, include: [ { association: db.OwnerEntity.Entity, // required: false, include: [ { association: db.Entity.EntityUsers, required: false, where: { userId: request.user?.id ?? null } } ] } ] } ] }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] }).then(translationArtifactVersion => { if (translationArtifactVersion) { response.display("translation-artifact-version", { user: request.user, pageTitle: "Translation Artifact - Mantra", translationArtifactVersion: translationArtifactVersion, }) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId') .get(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, }, { association: db.TranslationChapter.TranslationChapterTranslators, include: [ { association: db.TranslationChapterTranslator.Translator, include: [ { association: db.Entity.EntityEmail, include: [ { association: db.EntityEmail.Email } ] } ] } ] }, { association: db.TranslationChapter.TranslationChapterProofReaders, }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.BackTranslationFrom }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }).then(translationChapter => { if (translationChapter) { response.display("translate-chapter", { user: request.user, pageTitle: `Translate Chapter ${translationChapter.name}`, translationChapter: translationChapter }) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/view') .get(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, required: true }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] } ] } ] }).then(translationChapter => { if (translationChapter) { response.display("translate-chapter-view", { user: request.user, pageTitle: `Translate Chapter ${translationChapter.name}`, translatedChapterOutput: markdownProducer.produceHtml(translationChapter), translationChapter: translationChapter }) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/html') .get(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, required: true }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] } ] } ] }).then(translationChapter => { if (translationChapter) { response.contentType = "text/plain" response.send(markdownProducer.produceHtml(translationChapter)) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/markdown') .get(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, required: true }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] } ] } ] }).then(translationChapter => { if (translationChapter) { response.contentType = "text/plain" response.send(markdownProducer.produceMarkdownString(tokens)) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/t/:chunkIndex') .get(function(request, response, next) { const previousIndex = Number(request.params.chunkIndex)-1 const nextIndex = Number(request.params.chunkIndex)+1 db.TranslationChunk.findAll({ where: { translationChapterId: request.params.chapterId, index: { [Op.between]: [ previousIndex, nextIndex ], } }, limit: 3, include: [ { association: db.TranslationChunk.Translation }, { association: db.TranslationChunk.TranslationChapter, required: true, include: [ { association: db.TranslationChapter.TranslationArtifactVersion, required: true, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] } ] } ] } ] }).then(translationChunks => { if (translationChunks.length > 0) { const translationChunk = translationChunks.find(translationChunk => translationChunk.index == Number(request.params.chunkIndex)) if (translationChunk) { response.display("translate-chunk", { user: request.user, pageTitle: `Translate ${translationChunk.translationChapter.translationArtifactVersion.artifactVersion.artifact.name}`, translationChunk: translationChunk, previousTranslationChunk: translationChunks.find(translationChunk => translationChunk.index == previousIndex), nextTranslationChunk: translationChunks.find(translationChunk => translationChunk.index == nextIndex) }) } else { response.redirect(`/translate/${request.params.id}/chapter/${request.params.chapterId}`) } } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.TranslationChunk.findOne({ where: { translationChapterId: request.params.chapterId, index: request.params.chunkIndex }, include: [ { association: db.TranslationChunk.Translation }, { association: db.TranslationChunk.TranslationChapter, required: true, include: [ { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] } ] } ] } ] }).then(async (translationChunk) => { if (translationChunk) { if (translationChunk.translation) { translationChunk.translation.text = request.body.translatedText await translationChunk.translation.save() } else { translation = await db.Translation.create({ creatorId: request.user.id, translationChunkId: translationChunk.id, text: request.body.translatedText, translationArtifactVersionId: request.params.id }) } response.redirect(`/translate/${request.params.id}/chapter/${request.params.chapterId}/t/${Number(request.params.chunkIndex)+1}`) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/back') .post(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.Dialect, }, { association: db.TranslationArtifactVersion.TranslationChapters, include: [ { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation, } ] } ] }, { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.BackTranslation, }, { association: db.TranslationArtifactVersion.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((translationArtifactVersion) => { if (translationArtifactVersion) { if (translationArtifactVersion.backTranslation) { // translationArtifactVersion has a back translation...xx§ return translationArtifactVersion.backTranslation } else { return db.TranslationArtifactVersion.create({ creatorId: request.user.id, name: translationArtifactVersion.artifactVersion.artifact.dialect.name, artifactVersionId: translationArtifactVersion.artifactVersionId, dialectId: translationArtifactVersion.dialect.id, visibility: translationArtifactVersion.visibility, backTranslationFromId: translationArtifactVersion.id, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] }, translationChapters: translationArtifactVersion.translationChapters.map(translationChapter => { return { creatorId: request.user.id, chapterId: translationChapter.chapterId, index: translationChapter.index, translationChunks: translationChapter.translationChunks.map(translationChunk => { return { creatorId: request.user.id, chunkId: translationChunk.chunkId, text: translationChunk.translation.text, index: translationChunk.index } }) } }) }, { include: [ { association: db.TranslationArtifactVersion.TranslationChapters, include: [ { association: db.TranslationChapter.TranslationChunks } ] }, { association: db.TranslationArtifactVersionCampaign.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }) } } else { return null } }).then(translationArtifactVersion => { if (translationArtifactVersion) { response.redirect(`/translate/${translationArtifactVersion.id}`) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/campaigns') .get(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.TranslationArtifactVersionCampaigns, include: [ { association: db.TranslationArtifactVersionCampaign.Campaign, } ] }, { association: db.TranslationArtifactVersion.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(translationArtifactVersion => { if (translationArtifactVersion) { if (translationArtifactVersion.translationArtifactVersionCampaigns.length == 0) { response.redirect(`/translate/${request.params.id}/campaigns/create`) } else if (translationArtifactVersion.translationArtifactVersionCampaigns.length == 1) { response.redirect(`/campaigns/${translationArtifactVersion.translationArtifactVersionCampaigns[0].campaignId}`) } else { // TODO: Display translation artifact campaign... next() } } else { next() } }) }) router.route('/:id/campaigns/create') .get(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionCampaigns, include: [ { association: db.TranslationArtifactVersionCampaign.Campaign, } ] }, { association: db.TranslationArtifactVersion.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 ?? nulls } } ] } ] } ] } ] }).then(translationArtifactVersion => { if (translationArtifactVersion) { // TODO: Check if campaign exits... response.display("campaign-form", { user: request.user, pageTitle: "Campaign - Mantra", campaign: { name: `Campaign for ${translationArtifactVersion.name} translation of ${translationArtifactVersion.artifactVersion.artifact.name}` }, translationArtifactVersions: [translationArtifactVersion] }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionCampaigns, include: [ { association: db.TranslationArtifactVersionCampaign.Campaign, } ] }, { association: db.TranslationArtifactVersion.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 (translationArtifactVersion) => { if (translationArtifactVersion) { // TODO: Create campaign... 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: [ { creatorId: request.user.id, translationArtifactVersionId: translationArtifactVersion.id, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] }, satoshis: request.body.satoshis } ] }, { 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/pledges') .get(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.TranslationArtifactVersionPledges, required: true, include: [ { association: db.TranslationArtifactVersionPledge.Pledge, required: true } ] } ] }).then(translationArtifactVersion => { if (translationArtifactVersion) { if (translationArtifactVersion.translationArtifactVersionPledges.length == 1) { response.redirect(`/pledges/${translationArtifactVersion.translationArtifactVersionPledges[0].campaignId}`) } else { // TODO: Display translation artifact campaign... next() } } else { response.redirect(`/translate/${request.params.id}/pledges/create`) } }) }) router.route('/:id/pledges/create') .get(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionPledges, required: false, include: [ { association: db.TranslationArtifactVersionPledge.Pledge, required: false } ] } ] }).then(translationArtifactVersion => { if (translationArtifactVersion) { response.display("pledge-form", { user: request.user, pageTitle: "Pledge - Mantra", campaign: { name: `Pledge for ${translationArtifactVersion.name} translation of ${translationArtifactVersion.artifactVersion.artifact.name}`, }, translationArtifactVersions: [translationArtifactVersion] }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.TranslationArtifactVersion.findByPk(request.params.id, { include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact } ] }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionPledges, required: false, include: [ { association: db.TranslationArtifactVersionPledge.Pledge, required: false } ] } ] }).then(async (translationArtifactVersion) => { if (translationArtifactVersion) { // TODO: Create campaign... const pledge = await db.Pledge.create({ creatorId: request.user.id, message: request.body.message, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId } ] }, translationArtifactVersionPledges: [ { creatorId: request.user.id, translationArtifactVersionId: translationArtifactVersion.id, owner: { ownerEntities: [ { entityId: request.user.individualEntityUser.entityUser.entityId, } ] }, satoshis: request.body.satoshis } ] }, { include: [ { association: db.Pledge.TranslationArtifactVersionPledges, include: [ { association: db.TranslationArtifactVersionPledge.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }, { association: db.Pledge.Owner, include: [ { association: db.Owner.OwnerEntities } ] } ] }) response.redirect(`/pledges/${pledge.id}`) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/translator') .get(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, }, { association: db.TranslationChapter.TranslationChapterTranslators, include: [ { association: db.TranslationChapterTranslator.Translator, include: [ { association: db.Entity.EntityEmail, include: [ { association: db.EntityEmail.Email } ] } ] } ] }, { association: db.TranslationChapter.TranslationChapterProofReaders, }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.BackTranslationFrom }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }).then(translationChapter => { if (translationChapter) { response.display("translate-chapter-translator-form", { user: request.user, pageTitle: `Translate Chapter ${translationChapter.name}`, translationChapter: translationChapter }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.TranslationChapter.findByPk(request.params.chapterId, { include: [ { association: db.TranslationChapter.Chapter, }, { association: db.TranslationChapter.TranslationChapterTranslators, }, { association: db.TranslationChapter.TranslationChapterProofReaders, }, { association: db.TranslationChapter.TranslationChunks, include: [ { association: db.TranslationChunk.Translation } ] }, { association: db.TranslationChapter.TranslationArtifactVersion, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, include: [ { association: db.ArtifactVersion.Artifact, include: [ { association: db.Artifact.Dialect } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.BackTranslationFrom }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }).then(async (translationChapter) => { if (translationChapter) { // TODO: Check if translationChapter has a TranslationChapterTranslator with this email... // TODO: FindOrCreate Email const [email, created] = await db.Email.findOrCreate({ where: { address: request.body.translator }, include: [ { association: db.Email.EntityEmails, required: false, where: { creatorId: request.user.id } }, { association: db.Email.UserEmail, include: [ { association: db.UserEmail.User, include: [ { association: db.User.IndividualEntityUser, include: [ { association: db.IndividualEntityUser.EntityUser } ] } ] } ] } ], defaults: { address: request.body.translator } }) if (email.userEmail) { // if email has user associated with it tie that users individual entity to a new TranslationChapterTranslator object await db.TranslationChapterTranslator.create({ translationChapterId: translationChapter.id, creatorId: request.user.id, translatorId: email.userEmail.user.individualEntityUser.entityUser.entityId }) } else if (email.entityEmails?.length > 0) { // TODO: If email has an EntityEmail (which has this user as a creator) tie that entityEmail to a new TranslationChapterTranslator await db.TranslationChapterTranslator.create({ translationChapterId: translationChapter.id, creatorId: request.user.id, translatorId: email.entityEmails[0].entityId }) } else { // if email doesn't have a user/entityEmail associated with it (newly created) create an EntityEmail and tie it to a new TranslationChapterTranslator object await db.TranslationChapterTranslator.create({ translationChapterId: translationChapter.id, creatorId: request.user.id, translator: { name: idGenerator.generateRandomAlphanumeric(), type: "individual", entityEmail: { creatorId: request.user.id, emailAddress: email.address, type: 'translator' } } }, { include: [ { association: db.TranslationChapterTranslator.Translator, include: [ { association: db.Entity.EntityEmail } ] } ] }) } response.redirect(`/translate/${translationChapter.translationArtifactVersion.id}/chapter/${translationChapter.id}`) } else { next() } }).catch(error => { next(error) }) }) router.route('/:id/chapter/:chapterId/translator/:translatorId') .get(function(request, response, next) { db.TranslationChapterTranslator.findByPk(request.params.translatorId, { include: [ { association: db.TranslationChapterTranslator.TranslationChapter, required: true, include: [ { association: db.TranslationChapter.TranslationArtifactVersion, required: true, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, required: true, include: [ { association: db.ArtifactVersion.Artifact, required: true, include: [ { association: db.Artifact.Dialect }, { association: db.Artifact.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 } } ] } ] } ] } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.BackTranslationFrom }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }, { association: db.TranslationChapterTranslator.Translator, include: [ { association: db.Entity.EntityEmail, include: [ { association: db.EntityEmail.Email } ] } ] } ] }).then(translationChapterTranslator => { if (translationChapterTranslator) { response.display("translate-chapter-translator-remove", { user: request.user, pageTitle: `Translator ${translationChapterTranslator.name}`, translationChapterTranslator: translationChapterTranslator }) } else { next() } }).catch(error => { next(error) }) }) .post(function(request, response, next) { db.TranslationChapterTranslator.findByPk(request.params.translatorId, { include: [ { association: db.TranslationChapterTranslator.TranslationChapter, required: true, include: [ { association: db.TranslationChapter.TranslationArtifactVersion, required: true, include: [ { association: db.TranslationArtifactVersion.ArtifactVersion, required: true, include: [ { association: db.ArtifactVersion.Artifact, required: true, include: [ { association: db.Artifact.Dialect }, { association: db.Artifact.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 } } ] } ] } ] } ] } ] }, { association: db.TranslationArtifactVersion.Dialect }, { association: db.TranslationArtifactVersion.BackTranslationFrom }, { association: db.TranslationArtifactVersion.TranslationArtifactVersionEditor, } ] } ] }, { association: db.TranslationChapterTranslator.Translator, include: [ { association: db.Entity.EntityEmail, include: [ { association: db.EntityEmail.Email } ] } ] } ] }).then(async (translationChapterTranslator) => { if (translationChapterTranslator) { await translationChapterTranslator.destroy() response.redirect(`/translate/${translationChapterTranslator.translationChapter.translationArtifactVersion.id}/chapter/${translationChapterTranslator.translationChapter.id}`) } else { next() } }).catch(error => { next(error) }) }) return router; };