@jsreport/jsreport-core
Version:
javascript based business reporting
231 lines (172 loc) • 7.33 kB
JavaScript
const Request = require('../../shared/request')
module.exports = async (reporter) => {
if (
reporter.options.migrateResourcesToAssets === false ||
reporter.documentStore.collection('scripts') == null ||
reporter.documentStore.collection('data') == null
) {
return
}
const migrated = await reporter.settings.findValue('core-migrated-resources')
if (migrated) {
return
}
const req = Request({})
await reporter.documentStore.beginTransaction(req)
try {
const templateIds = await reporter.documentStore.collection('templates').find({}, { _id: 1 }, req)
if (templateIds.length !== 0) {
reporter.logger.debug('Running migration "resourcesToAssets"')
}
const templateToAssetResourcesMap = new Map()
const dataToAssetMap = new Map()
const dataEntitiesToRemove = []
for (const templateId of templateIds) {
const template = await reporter.documentStore.collection('templates').findOne({ _id: templateId._id }, req)
if (template.resources == null) {
continue
}
if (Array.isArray(template.resources.items)) {
for (const dataItem of template.resources.items) {
const dataEntity = await reporter.documentStore.collection('data').findOne({ shortid: dataItem.shortid }, req)
if (dataEntity) {
let newAsset
if (dataToAssetMap.has(dataEntity._id)) {
newAsset = dataToAssetMap.get(dataEntity._id)
} else {
const assetProps = {
content: Buffer.from(dataEntity.dataJson || ''),
folder: dataEntity.folder || null
}
if (dataEntity.readPermissions != null) {
assetProps.readPermissions = dataEntity.readPermissions
}
if (dataEntity.editPermissions != null) {
assetProps.editPermissions = dataEntity.editPermissions
}
newAsset = await insertUnique(reporter, 'assets', `${dataEntity.name}.json`, assetProps, req)
dataToAssetMap.set(dataEntity._id, newAsset)
}
const assetResources = templateToAssetResourcesMap.get(template._id) || []
assetResources.push({
...newAsset,
originalName: dataEntity.name
})
templateToAssetResourcesMap.set(template._id, assetResources)
dataEntitiesToRemove.push(dataEntity._id)
}
}
}
const templateAssetResources = templateToAssetResourcesMap.get(template._id) || []
if (templateAssetResources.length > 0) {
const scriptProps = {
content: (
`
// THIS SCRIPT WAS GENERATED BY MIGRATION IN V3, IT PROVIDES BACKWARD COMPATIBILITY
// WITH THE DEPRECATED jsreport-resources https://jsreport.net/learn/resources
// THE RECOMMENDATION NOW IS TO USE jsreport-localization https://jsreport.net/learn/localization
// SO WHEN YOU DECIDE TO USE jsreport-localization TO FULLY REPLACE THE jsreport-resources
// JUST REMOVE THIS SCRIPT FROM YOUR TEMPLATE AND DELETE IT
const jsreport = require('jsreport-proxy')
async function beforeRender (req, res) {
req.options.language = req.options.language || req.template.localization?.language
const defaultLanguage = ${template.resources.defaultLanguage != null ? '\'' + template.resources.defaultLanguage + '\'' : 'undefined'}
const assetsResources = [${templateAssetResources.map(a => `{ name: '${a.originalName}', shortid: '${a.shortid}' }`).join(', ')}]
const resources = await Promise.all(assetsResources.map(async (r) => {
const asset = await jsreport.documentStore.collection('assets').findOne({ shortid: r.shortid })
if (asset == null) {
throw new Error(\`Asset resources with shortid \${r.shortid} was not found (resource lookup)\`)
}
asset.resourceName = r.name
asset.content = asset.content.toString()
return asset
}))
resources.forEach((r) => {
r.dataJson = r.content
r.data = JSON.parse(r.content)
})
req.options.resources = resources
req.data.$resources = resources
const resourcesByName = {}
resources.forEach((r) => {
resourcesByName[r.resourceName] = r.data
})
req.options.resource = resourcesByName
req.data.$resource = resourcesByName
const isLocalizedRequest = req.options.language != null || defaultLanguage != null
if (isLocalizedRequest) {
let languageUsed
let applicableResources = []
if (req.options.language) {
languageUsed = req.options.language
applicableResources = resources.filter((r) => r.resourceName.startsWith(\`\${languageUsed}-\`))
}
if (!applicableResources.length && defaultLanguage) {
languageUsed = defaultLanguage
applicableResources = resources.filter((r) => r.resourceName.startsWith(\`\${languageUsed}-\`))
}
console.log(\`Found \${applicableResources.length} resources for language "\${languageUsed}"\`)
req.options.localizedResources = applicableResources
req.data.$localizedResources = applicableResources
const localizedResourceByName = {}
applicableResources.forEach((r) => {
localizedResourceByName[r.resourceName.substring(\`\${languageUsed}-\`.length)] = r.data
})
req.options.localizedResource = applicableResources.length === 1 ? applicableResources[0].data : localizedResourceByName
req.data.$localizedResource = req.options.localizedResource
}
}
`
),
folder: template.folder || null
}
if (template.readPermissions != null) {
scriptProps.readPermissions = template.readPermissions
}
if (template.editPermissions != null) {
scriptProps.editPermissions = template.editPermissions
}
const newScript = await insertUnique(reporter, 'scripts', `${template.name}_resources`, scriptProps, req)
template.scripts = template.scripts || []
template.scripts.unshift({
shortid: newScript.shortid
})
}
template.resources = null
await reporter.documentStore.collection('templates').update({ _id: template._id }, { $set: template }, req)
}
for (const dataEntityId of dataEntitiesToRemove) {
await reporter.documentStore.collection('data').remove({ _id: dataEntityId }, req)
}
if (templateIds.length !== 0) {
reporter.logger.debug('Migration "resourcesToAssets" finished')
}
await reporter.documentStore.commitTransaction(req)
await reporter.settings.addOrSet('core-migrated-resources', true)
} catch (migrationErr) {
await reporter.documentStore.rollbackTransaction(req)
migrationErr.message = `Migration "resourcesToAssets" failed: ${migrationErr.message}`
throw migrationErr
}
}
async function insertUnique (reporter, collectionName, baseName, entity, req) {
let newEntity
let tryCount = 0
while (newEntity == null) {
try {
const entityName = '_'.repeat(tryCount) + baseName
newEntity = await reporter.documentStore.collection(collectionName).insert({
...entity,
name: entityName
}, req)
return newEntity
} catch (insertError) {
tryCount++
if (insertError.code === 'DUPLICATED_ENTITY') {
continue
} else {
throw insertError
}
}
}
}