adapt-authoring-adaptframework 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,8 +2,8 @@ import _ from 'lodash'
|
|
|
2
2
|
import { App, Hook } from 'adapt-authoring-core'
|
|
3
3
|
import { createWriteStream } from 'fs'
|
|
4
4
|
import AdaptCli from 'adapt-cli'
|
|
5
|
-
import
|
|
6
|
-
import fs from 'fs
|
|
5
|
+
import FWUtils from './AdaptFrameworkUtils.js'
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
7
|
import path from 'upath'
|
|
8
8
|
import semver from 'semver'
|
|
9
9
|
import zipper from 'zipper'
|
|
@@ -175,7 +175,9 @@ class AdaptFrameworkBuild {
|
|
|
175
175
|
if (!this.expiresAt) {
|
|
176
176
|
this.expiresAt = await AdaptFrameworkBuild.getBuildExpiry()
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
// random suffix to account for parallel builds executed at exactly the same millisecond
|
|
179
|
+
const randomSuffix = `_${Math.floor(Math.random() * 1000).toString().padStart(4, '0')}`
|
|
180
|
+
this.dir = path.resolve(framework.getConfig('buildDir'), Date.now() + randomSuffix)
|
|
179
181
|
this.buildDir = path.join(this.dir, 'build')
|
|
180
182
|
this.courseDir = path.join(this.buildDir, 'course')
|
|
181
183
|
|
|
@@ -185,9 +187,9 @@ class AdaptFrameworkBuild {
|
|
|
185
187
|
await this.ensureDir(this.buildDir)
|
|
186
188
|
await this.ensureDir(cacheDir)
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
FWUtils.logDir('dir', this.dir)
|
|
191
|
+
FWUtils.logDir('buildDir', this.buildDir)
|
|
192
|
+
FWUtils.logDir('cacheDir', this.cacheDir)
|
|
191
193
|
|
|
192
194
|
await this.loadCourseData()
|
|
193
195
|
|
|
@@ -200,11 +202,11 @@ class AdaptFrameworkBuild {
|
|
|
200
202
|
|
|
201
203
|
await this.writeContentJson()
|
|
202
204
|
|
|
203
|
-
|
|
205
|
+
FWUtils.logDir('courseDir', this.courseDir)
|
|
204
206
|
|
|
205
207
|
if (!this.isExport) {
|
|
206
208
|
try {
|
|
207
|
-
|
|
209
|
+
FWUtils.logMemory()
|
|
208
210
|
await AdaptCli.buildCourse({
|
|
209
211
|
cwd: this.dir,
|
|
210
212
|
sourceMaps: !this.isPublish,
|
|
@@ -212,9 +214,9 @@ class AdaptFrameworkBuild {
|
|
|
212
214
|
cachePath: path.resolve(cacheDir, this.courseId),
|
|
213
215
|
logger: { log: (...args) => App.instance.logger.log('debug', 'adapt-cli', ...args) }
|
|
214
216
|
})
|
|
215
|
-
|
|
217
|
+
FWUtils.logMemory()
|
|
216
218
|
} catch (e) {
|
|
217
|
-
|
|
219
|
+
FWUtils.logMemory()
|
|
218
220
|
throw App.instance.errors.FW_CLI_BUILD_FAILED
|
|
219
221
|
.setData(e)
|
|
220
222
|
}
|
|
@@ -397,10 +399,11 @@ class AdaptFrameworkBuild {
|
|
|
397
399
|
*/
|
|
398
400
|
async copySource () {
|
|
399
401
|
const { path: fwPath } = await App.instance.waitForModule('adaptframework')
|
|
400
|
-
const BLACKLIST = ['.git', '.DS_Store', 'thumbs.db', 'node_modules', 'course']
|
|
402
|
+
const BLACKLIST = ['.git', '.DS_Store', 'thumbs.db', 'node_modules', 'course', 'migrations']
|
|
401
403
|
const ENABLED_PLUGINS = this.enabledPlugins.map(p => p.name)
|
|
402
404
|
const srcDir = path.join(fwPath, 'src')
|
|
403
|
-
await fs.
|
|
405
|
+
await fs.cp(fwPath, this.dir, {
|
|
406
|
+
recursive: true,
|
|
404
407
|
filter: f => {
|
|
405
408
|
f = path.normalize(f)
|
|
406
409
|
const [type, name] = path.relative(srcDir, f).split('/')
|
|
@@ -456,8 +459,8 @@ class AdaptFrameworkBuild {
|
|
|
456
459
|
return Promise.all(data.map(async ({ dir, fileName, data }) => {
|
|
457
460
|
await this.ensureDir(dir)
|
|
458
461
|
const filepath = path.join(dir, fileName)
|
|
459
|
-
const returnData = await
|
|
460
|
-
|
|
462
|
+
const returnData = await FWUtils.writeJson(filepath, data)
|
|
463
|
+
FWUtils.log('debug', 'WRITE', filepath)
|
|
461
464
|
return returnData
|
|
462
465
|
}))
|
|
463
466
|
}
|
|
@@ -468,9 +471,9 @@ class AdaptFrameworkBuild {
|
|
|
468
471
|
*/
|
|
469
472
|
async createPreview () {
|
|
470
473
|
const tempName = `${this.dir}_temp`
|
|
471
|
-
await fs.
|
|
472
|
-
await fs.
|
|
473
|
-
await fs.
|
|
474
|
+
await fs.rename(path.join(this.dir, 'build'), tempName)
|
|
475
|
+
await fs.rm(this.dir, { recursive: true })
|
|
476
|
+
await fs.rename(tempName, this.dir)
|
|
474
477
|
this.location = this.dir
|
|
475
478
|
}
|
|
476
479
|
|
|
@@ -486,7 +489,7 @@ class AdaptFrameworkBuild {
|
|
|
486
489
|
}
|
|
487
490
|
const outputPath = `${this.dir}.zip`
|
|
488
491
|
await zipper.zip(zipPath, outputPath, { removeSource: true })
|
|
489
|
-
await fs.
|
|
492
|
+
await fs.rm(this.dir, { recursive: true })
|
|
490
493
|
this.location = outputPath
|
|
491
494
|
}
|
|
492
495
|
|
|
@@ -518,7 +521,13 @@ class AdaptFrameworkBuild {
|
|
|
518
521
|
const mongodb = await App.instance.waitForModule('mongodb')
|
|
519
522
|
const query = { action: this.action, createdBy: this.userId }
|
|
520
523
|
const oldBuilds = await mongodb.find(this.collectionName, query)
|
|
521
|
-
await Promise.all(oldBuilds.map(b =>
|
|
524
|
+
await Promise.all(oldBuilds.map(async b => {
|
|
525
|
+
try {
|
|
526
|
+
await fs.rm(b.location, { recursive: true })
|
|
527
|
+
} catch (e) {
|
|
528
|
+
if (e.code !== 'ENOENT') throw e
|
|
529
|
+
}
|
|
530
|
+
}))
|
|
522
531
|
return mongodb.deleteMany(this.collectionName, query)
|
|
523
532
|
}
|
|
524
533
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { App } from 'adapt-authoring-core'
|
|
2
|
-
import fs from 'fs
|
|
2
|
+
import fs from 'fs/promises'
|
|
3
3
|
import { glob } from 'glob'
|
|
4
4
|
import octopus from 'adapt-octopus'
|
|
5
5
|
import path from 'upath'
|
|
6
6
|
import semver from 'semver'
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import FWUtils from './AdaptFrameworkUtils.js'
|
|
9
9
|
|
|
10
10
|
import ComponentTransform from './migrations/component.js'
|
|
11
11
|
import ConfigTransform from './migrations/config.js'
|
|
@@ -217,9 +217,9 @@ class AdaptFrameworkImport {
|
|
|
217
217
|
*/
|
|
218
218
|
this.jsonschema = jsonschema
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
FWUtils.log('info', `running with settings ${JSON.stringify(this.settings, null, 2)}`)
|
|
221
|
+
FWUtils.log('debug', 'IMPORT_SETTINGS', JSON.stringify(this.settings, null, 2))
|
|
222
|
+
FWUtils.log('debug', 'IMPORT_USER', this.userId)
|
|
223
223
|
|
|
224
224
|
const { isDryRun, importContent, importPlugins } = this.settings
|
|
225
225
|
const tasks = [
|
|
@@ -257,8 +257,8 @@ class AdaptFrameworkImport {
|
|
|
257
257
|
const nestDir = `${this.unzipPath}/${files[0]}`
|
|
258
258
|
await fs.stat(`${nestDir}/package.json`)
|
|
259
259
|
const newDir = path.join(`${this.unzipPath}_2`)
|
|
260
|
-
await fs.
|
|
261
|
-
await fs.
|
|
260
|
+
await fs.rename(nestDir, newDir)
|
|
261
|
+
await fs.rm(this.unzipPath, { recursive: true })
|
|
262
262
|
this.unzipPath = newDir
|
|
263
263
|
}
|
|
264
264
|
} catch (e) {
|
|
@@ -269,15 +269,15 @@ class AdaptFrameworkImport {
|
|
|
269
269
|
await fs.stat(f)
|
|
270
270
|
this.coursePath = f
|
|
271
271
|
}))
|
|
272
|
-
|
|
272
|
+
FWUtils.logDir('unzipPath', this.unzipPath)
|
|
273
273
|
|
|
274
274
|
if (!this.coursePath) {
|
|
275
275
|
throw App.instance.errors.FW_IMPORT_INVALID_COURSE
|
|
276
276
|
}
|
|
277
|
-
|
|
277
|
+
FWUtils.logDir('coursePath', this.coursePath)
|
|
278
278
|
|
|
279
279
|
try {
|
|
280
|
-
/** @ignore */this.pkg = await
|
|
280
|
+
/** @ignore */this.pkg = await FWUtils.readJson(`${this.unzipPath}/package.json`)
|
|
281
281
|
} catch (e) {
|
|
282
282
|
throw App.instance.errors.FW_IMPORT_INVALID
|
|
283
283
|
}
|
|
@@ -294,7 +294,7 @@ class AdaptFrameworkImport {
|
|
|
294
294
|
this.statusReport.info.push({ code: 'MIGRATE_CONTENT', data })
|
|
295
295
|
}
|
|
296
296
|
await this.convertSchemas()
|
|
297
|
-
|
|
297
|
+
FWUtils.log('debug', 'preparation tasks completed successfully')
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
/**
|
|
@@ -304,7 +304,7 @@ class AdaptFrameworkImport {
|
|
|
304
304
|
async convertSchemas () {
|
|
305
305
|
return octopus.runRecursive({
|
|
306
306
|
cwd: this.unzipPath,
|
|
307
|
-
logger: { log: (...args) =>
|
|
307
|
+
logger: { log: (...args) => FWUtils.log('debug', ...args) }
|
|
308
308
|
})
|
|
309
309
|
}
|
|
310
310
|
|
|
@@ -319,11 +319,11 @@ class AdaptFrameworkImport {
|
|
|
319
319
|
}
|
|
320
320
|
try {
|
|
321
321
|
const customStyle = await fs.readFile(customStylePath, 'utf8')
|
|
322
|
-
const courseJson = await
|
|
323
|
-
await
|
|
324
|
-
|
|
322
|
+
const courseJson = await FWUtils.readJson(courseJsonPath)
|
|
323
|
+
await FWUtils.writeJson(courseJsonPath, { customStyle, ...courseJson })
|
|
324
|
+
FWUtils.log('info', 'patched course customStyle')
|
|
325
325
|
} catch (e) {
|
|
326
|
-
|
|
326
|
+
FWUtils.log('warn', 'failed to patch course customStyle', e)
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
329
|
|
|
@@ -333,12 +333,13 @@ class AdaptFrameworkImport {
|
|
|
333
333
|
async patchThemeName () {
|
|
334
334
|
const [configJsonPath] = await glob('**/config.json', { cwd: this.coursePath, absolute: true })
|
|
335
335
|
try {
|
|
336
|
-
const configJson = await
|
|
336
|
+
const configJson = await FWUtils.readJson(configJsonPath)
|
|
337
337
|
if (configJson._theme) return
|
|
338
|
-
|
|
339
|
-
|
|
338
|
+
configJson._theme = Object.values(this.usedContentPlugins).find(p => p.type === 'theme').name
|
|
339
|
+
await FWUtils.writeJson(configJsonPath, configJson)
|
|
340
|
+
FWUtils.log('info', 'patched config _theme')
|
|
340
341
|
} catch (e) {
|
|
341
|
-
|
|
342
|
+
FWUtils.log('warn', 'failed to patch config _theme', e)
|
|
342
343
|
}
|
|
343
344
|
}
|
|
344
345
|
|
|
@@ -350,14 +351,14 @@ class AdaptFrameworkImport {
|
|
|
350
351
|
this.assetData = []
|
|
351
352
|
const metaFiles = await glob(`${this.coursePath}/*/assets.json`, { absolute: true })
|
|
352
353
|
if (metaFiles.length) { // process included asset metadata
|
|
353
|
-
|
|
354
|
+
FWUtils.log('debug', 'processing metadata files', metaFiles)
|
|
354
355
|
await Promise.all(metaFiles.map(async f => {
|
|
355
|
-
const metaJson = await
|
|
356
|
+
const metaJson = await FWUtils.readJson(f)
|
|
356
357
|
Object.entries(metaJson).forEach(([filename, metadata]) => this.assetData.push({ filename, ...metadata }))
|
|
357
358
|
}))
|
|
358
359
|
} else { // process the file metadata manually
|
|
359
360
|
const assetFiles = await glob(`${this.coursePath}/*/*/*`, { absolute: true })
|
|
360
|
-
|
|
361
|
+
FWUtils.log('debug', 'processing asset files manually', assetFiles.length)
|
|
361
362
|
this.assetData.push(...assetFiles.map(f => Object.assign({}, { title: path.basename(f), filepath: f })))
|
|
362
363
|
}
|
|
363
364
|
const hasGlobalTags = !!this.tags.length
|
|
@@ -380,9 +381,9 @@ class AdaptFrameworkImport {
|
|
|
380
381
|
}
|
|
381
382
|
}
|
|
382
383
|
await Promise.all(usedPluginPaths.map(async p => {
|
|
383
|
-
const bowerJson = await
|
|
384
|
+
const bowerJson = await FWUtils.readJson(`${p}/bower.json`)
|
|
384
385
|
const { name, version, targetAttribute } = bowerJson
|
|
385
|
-
|
|
386
|
+
FWUtils.log('debug', 'found plugin', name)
|
|
386
387
|
this.usedContentPlugins[path.basename(p)] = { name, path: p, version, targetAttribute, type: getPluginType(bowerJson) }
|
|
387
388
|
}))
|
|
388
389
|
}
|
|
@@ -394,8 +395,8 @@ class AdaptFrameworkImport {
|
|
|
394
395
|
async loadCourseData () {
|
|
395
396
|
const files = await glob('**/*.json', { cwd: this.coursePath, absolute: true, ignore: { ignored: p => p.name === 'assets.json' } })
|
|
396
397
|
const mapped = await Promise.all(files.map(f => this.loadContentFile(f)))
|
|
397
|
-
this.statusReport.info.push({ code: 'CONTENT_IMPORTED', data:
|
|
398
|
-
|
|
398
|
+
this.statusReport.info.push({ code: 'CONTENT_IMPORTED', data: FWUtils.getImportContentCounts(this.contentJson) })
|
|
399
|
+
FWUtils.log('info', 'loaded course data successfully')
|
|
399
400
|
return mapped
|
|
400
401
|
}
|
|
401
402
|
|
|
@@ -404,7 +405,7 @@ class AdaptFrameworkImport {
|
|
|
404
405
|
* @return {Promise}
|
|
405
406
|
*/
|
|
406
407
|
async loadContentFile (filePath) {
|
|
407
|
-
const contents = await
|
|
408
|
+
const contents = await FWUtils.readJson(filePath)
|
|
408
409
|
if (contents._type === 'course') {
|
|
409
410
|
this.contentJson.course = contents
|
|
410
411
|
return
|
|
@@ -422,12 +423,12 @@ class AdaptFrameworkImport {
|
|
|
422
423
|
contents.forEach(c => {
|
|
423
424
|
this.contentJson.contentObjects[c._id] = c
|
|
424
425
|
if (!c._type) {
|
|
425
|
-
|
|
426
|
+
FWUtils.log('warn', App.instance.errors.FW_IMPORT_INVALID_CONTENT.setData({ item: c }))
|
|
426
427
|
this.statusReport.warn.push({ code: 'INVALID_CONTENT', data: c })
|
|
427
428
|
}
|
|
428
429
|
})
|
|
429
430
|
}
|
|
430
|
-
|
|
431
|
+
FWUtils.log('debug', 'LOAD_CONTENT', path.resolve(filePath))
|
|
431
432
|
}
|
|
432
433
|
|
|
433
434
|
/**
|
|
@@ -435,7 +436,7 @@ class AdaptFrameworkImport {
|
|
|
435
436
|
* @return {Promise}
|
|
436
437
|
*/
|
|
437
438
|
async runGruntTask (subTask, { outputDir, captureDir, outputFilePath }) {
|
|
438
|
-
const output = await
|
|
439
|
+
const output = await FWUtils.spawnPromise('npx', ['grunt', `migration:${subTask}`, `--outputdir=${outputDir}`, `--capturedir=${captureDir}`])
|
|
439
440
|
if (outputFilePath) await fs.writeFile(outputFilePath, output)
|
|
440
441
|
}
|
|
441
442
|
|
|
@@ -449,22 +450,22 @@ class AdaptFrameworkImport {
|
|
|
449
450
|
|
|
450
451
|
const folderName = `${this.userId}-migrations`
|
|
451
452
|
const relativePath = path.relative(this.framework.path, this.unzipPath)
|
|
452
|
-
const outputDir =
|
|
453
|
+
const outputDir = await FWUtils.exists(path.join(this.unzipPath, 'build'))
|
|
453
454
|
? path.join(relativePath, 'build')
|
|
454
455
|
: path.join(relativePath, 'src')
|
|
455
456
|
const captureDir = path.join('./', folderName)
|
|
456
457
|
|
|
457
|
-
|
|
458
|
-
|
|
458
|
+
FWUtils.logDir('captureDir', path.join(this.framework.path, captureDir))
|
|
459
|
+
FWUtils.logDir('outputDir', path.join(this.unzipPath, outputDir))
|
|
459
460
|
|
|
460
461
|
const opts = { outputDir, captureDir, outputFilePath: path.join(this.framework.path, 'migrations', `${this.userId}.txt`) }
|
|
461
462
|
await this.runGruntTask('capture', opts)
|
|
462
463
|
await this.runGruntTask('migrate', opts)
|
|
463
464
|
|
|
464
465
|
const captureFolder = path.join(this.framework.path, captureDir)
|
|
465
|
-
await fs.
|
|
466
|
+
await fs.rm(captureFolder, { recursive: true })
|
|
466
467
|
} catch (error) {
|
|
467
|
-
|
|
468
|
+
FWUtils.log('error', 'Migration process failed', error)
|
|
468
469
|
throw new Error(`Migration process failed: ${error.message}`)
|
|
469
470
|
}
|
|
470
471
|
}
|
|
@@ -505,7 +506,7 @@ class AdaptFrameworkImport {
|
|
|
505
506
|
if (course.tags) {
|
|
506
507
|
course.tags = course.tags.map(t => existingTagMap[t])
|
|
507
508
|
}
|
|
508
|
-
|
|
509
|
+
FWUtils.log('debug', 'imported tags successfully')
|
|
509
510
|
}
|
|
510
511
|
|
|
511
512
|
/**
|
|
@@ -539,7 +540,7 @@ class AdaptFrameworkImport {
|
|
|
539
540
|
}
|
|
540
541
|
imagesImported++
|
|
541
542
|
}))
|
|
542
|
-
|
|
543
|
+
FWUtils.log('debug', 'imported course assets successfully')
|
|
543
544
|
this.statusReport.info.push({ code: 'ASSETS_IMPORTED_SUCCESSFULLY', data: { count: imagesImported } })
|
|
544
545
|
}
|
|
545
546
|
|
|
@@ -571,7 +572,7 @@ class AdaptFrameworkImport {
|
|
|
571
572
|
const { version: installedVersion, isLocalInstall } = installedP
|
|
572
573
|
if (semver.lt(importVersion, installedVersion)) {
|
|
573
574
|
this.statusReport.info.push({ code: 'PLUGIN_INSTALL_MIGRATING', data: { name: p, installedVersion, importVersion } })
|
|
574
|
-
|
|
575
|
+
FWUtils.log('debug', `migrating '${p}@${importVersion}' during import, installed version is newer (${installedVersion})`)
|
|
575
576
|
this.pluginsToMigrate.push(p)
|
|
576
577
|
return
|
|
577
578
|
}
|
|
@@ -580,12 +581,12 @@ class AdaptFrameworkImport {
|
|
|
580
581
|
}
|
|
581
582
|
if (semver.eq(importVersion, installedVersion)) {
|
|
582
583
|
this.statusReport.info.push({ code: 'PLUGIN_INSTALL_NOT_NEWER', data: { name: p, installedVersion, importVersion } })
|
|
583
|
-
|
|
584
|
+
FWUtils.log('debug', `not updating '${p}@${importVersion}' during import, installed version is equal to (${installedVersion})`)
|
|
584
585
|
return
|
|
585
586
|
}
|
|
586
587
|
if (!isLocalInstall) {
|
|
587
588
|
this.statusReport.warn.push({ code: 'MANAGED_PLUGIN_INSTALL_SKIPPED', data: { name: p, installedVersion, importVersion } })
|
|
588
|
-
|
|
589
|
+
FWUtils.log('debug', `cannot update '${p}' during import, plugin managed via UI`)
|
|
589
590
|
}
|
|
590
591
|
pluginsToUpdate.push(p)
|
|
591
592
|
})
|
|
@@ -600,10 +601,10 @@ class AdaptFrameworkImport {
|
|
|
600
601
|
try {
|
|
601
602
|
// try and infer a targetAttribute if there isn't one
|
|
602
603
|
const pluginBowerPath = path.join(this.usedContentPlugins[p].path, 'bower.json')
|
|
603
|
-
const bowerJson = await
|
|
604
|
+
const bowerJson = await FWUtils.readJson(pluginBowerPath)
|
|
604
605
|
if (!bowerJson.targetAttribute) {
|
|
605
606
|
bowerJson.targetAttribute = `_${bowerJson.component || bowerJson.extension || bowerJson.menu || bowerJson.theme}`
|
|
606
|
-
await
|
|
607
|
+
await FWUtils.writeJson(pluginBowerPath, bowerJson)
|
|
607
608
|
}
|
|
608
609
|
if (!this.settings.isDryRun) {
|
|
609
610
|
const [pluginData] = await this.contentplugin.installPlugins([[p, this.usedContentPlugins[p].path]], { strict: true })
|
|
@@ -612,7 +613,7 @@ class AdaptFrameworkImport {
|
|
|
612
613
|
this.statusReport.info.push({ code: 'INSTALL_PLUGIN', data: { name: p, version: bowerJson.version } })
|
|
613
614
|
} catch (e) {
|
|
614
615
|
if (e.code !== 'EEXIST') {
|
|
615
|
-
|
|
616
|
+
FWUtils.log('error', 'PLUGIN_IMPORT_FAILED', p, e)
|
|
616
617
|
errors.push({ plugin: p, error: e.data.errors[0] })
|
|
617
618
|
} else {
|
|
618
619
|
errors.push(e)
|
|
@@ -627,7 +628,7 @@ class AdaptFrameworkImport {
|
|
|
627
628
|
this.componentNameMap = Object.values({ ...this.installedPlugins, ...this.newContentPlugins }).reduce((m, v) => {
|
|
628
629
|
return { ...m, [v.targetAttribute.slice(1)]: v.name }
|
|
629
630
|
}, {})
|
|
630
|
-
|
|
631
|
+
FWUtils.log('debug', 'imported course plugins successfully')
|
|
631
632
|
}
|
|
632
633
|
|
|
633
634
|
/**
|
|
@@ -665,7 +666,7 @@ class AdaptFrameworkImport {
|
|
|
665
666
|
}
|
|
666
667
|
}
|
|
667
668
|
if (errors.length) throw App.instance.errors.FW_IMPORT_CONTENT_FAILED.setData({ errors: errors.join('; ') })
|
|
668
|
-
|
|
669
|
+
FWUtils.log('debug', 'imported course data successfully')
|
|
669
670
|
}
|
|
670
671
|
|
|
671
672
|
/**
|
|
@@ -711,7 +712,7 @@ class AdaptFrameworkImport {
|
|
|
711
712
|
try {
|
|
712
713
|
this.extractAssets(schema.built.properties, insertData)
|
|
713
714
|
} catch (e) {
|
|
714
|
-
|
|
715
|
+
FWUtils.log('error', `failed to extract asset data for attribute '${e.attribute}' of schema '${schemaName}', ${e}`)
|
|
715
716
|
}
|
|
716
717
|
insertData = await schema.sanitise(insertData)
|
|
717
718
|
let doc
|
|
@@ -770,7 +771,7 @@ class AdaptFrameworkImport {
|
|
|
770
771
|
async cleanUp (error) {
|
|
771
772
|
try {
|
|
772
773
|
const tasks = [
|
|
773
|
-
fs.
|
|
774
|
+
fs.rm(this.unzipPath, { recursive: true })
|
|
774
775
|
]
|
|
775
776
|
if (error) {
|
|
776
777
|
tasks.push(
|
|
@@ -105,13 +105,13 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
105
105
|
const modsPath = path.resolve(this.path, '..', 'node_modules')
|
|
106
106
|
try {
|
|
107
107
|
await fs.stat(modsPath)
|
|
108
|
-
await fs.
|
|
108
|
+
await fs.readFile(path.resolve(this.path, 'package.json'))
|
|
109
109
|
if (!force) {
|
|
110
110
|
this.log('verbose', 'INSTALL no action, force !== true')
|
|
111
111
|
return
|
|
112
112
|
}
|
|
113
113
|
this.log('verbose', 'INSTALL forcing new framework install')
|
|
114
|
-
await fs.
|
|
114
|
+
await fs.rm(this.path, { recursive: true })
|
|
115
115
|
} catch (e) {
|
|
116
116
|
// if src and node_modules are missing, install required
|
|
117
117
|
}
|
|
@@ -119,10 +119,10 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
119
119
|
// move node_modules into place
|
|
120
120
|
this.log('verbose', 'INSTALL node_modules')
|
|
121
121
|
try {
|
|
122
|
-
await fs.
|
|
122
|
+
await fs.rm(modsPath, { recursive: true })
|
|
123
123
|
} catch (e) {}
|
|
124
124
|
// move node_modules so it can be shared with all builds
|
|
125
|
-
await fs.
|
|
125
|
+
await fs.rename(path.join(this.path, 'node_modules'), modsPath)
|
|
126
126
|
} catch (e) {
|
|
127
127
|
this.log('error', `failed to install framework, ${e.message}`)
|
|
128
128
|
throw this.app.errors.FW_INSTALL_FAILED
|
|
@@ -149,7 +149,7 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
149
149
|
* @return {Promise}
|
|
150
150
|
*/
|
|
151
151
|
async getManifestPlugins () {
|
|
152
|
-
const manifest = await
|
|
152
|
+
const manifest = await FWUtils.readJson(path.resolve(this.path, 'adapt.json'))
|
|
153
153
|
return Object.entries(manifest.dependencies)
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -3,7 +3,8 @@ import { App } from 'adapt-authoring-core'
|
|
|
3
3
|
import bytes from 'bytes'
|
|
4
4
|
import FrameworkBuild from './AdaptFrameworkBuild.js'
|
|
5
5
|
import FrameworkImport from './AdaptFrameworkImport.js'
|
|
6
|
-
import fs from 'fs'
|
|
6
|
+
import fs from 'fs/promises'
|
|
7
|
+
/* eslint-disable import/no-named-default */import { default as fsSync } from 'fs'
|
|
7
8
|
import path from 'upath'
|
|
8
9
|
import semver from 'semver'
|
|
9
10
|
import { spawn } from 'child_process'
|
|
@@ -51,7 +52,7 @@ class AdaptFrameworkUtils {
|
|
|
51
52
|
try {
|
|
52
53
|
const resolved = dir ? path.resolve(dir) : undefined
|
|
53
54
|
AdaptFrameworkUtils.log('verbose', 'DIR', label, resolved)
|
|
54
|
-
if (resolved) AdaptFrameworkUtils.log('verbose', 'DIR_MODE', label,
|
|
55
|
+
if (resolved) AdaptFrameworkUtils.log('verbose', 'DIR_MODE', label, fsSync.statSync(resolved).mode)
|
|
55
56
|
} catch (e) {
|
|
56
57
|
AdaptFrameworkUtils.log('warn', `failed to log dir ${label} (${dir}), ${e.code}`)
|
|
57
58
|
}
|
|
@@ -61,6 +62,26 @@ class AdaptFrameworkUtils {
|
|
|
61
62
|
AdaptFrameworkUtils.log('verbose', 'MEMORY', Object.entries(process.memoryUsage()).reduce((m, [k, v]) => Object.assign(m, { [k]: bytes.parse(v) }), {}))
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
static async readJson (filepath) {
|
|
66
|
+
return JSON.parse(await fs.readFile(filepath))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static writeJson (filepath, data) {
|
|
70
|
+
return fs.writeFile(filepath, (JSON.stringify(data, null, 2)))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static async exists (filepath) {
|
|
74
|
+
try {
|
|
75
|
+
await fs.stat(filepath)
|
|
76
|
+
return true
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (e.code === 'ENOENT') {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
throw e
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
64
85
|
/**
|
|
65
86
|
* Infers the framework action to be executed from a given request URL
|
|
66
87
|
* @param {external:ExpressRequest} req
|
|
@@ -220,11 +241,11 @@ class AdaptFrameworkUtils {
|
|
|
220
241
|
}
|
|
221
242
|
const filePath = path.resolve(buildData.location, req.path.slice(req.path.indexOf(id) + id.length + 1) || 'index.html')
|
|
222
243
|
try {
|
|
223
|
-
await
|
|
224
|
-
|
|
244
|
+
await AdaptFrameworkUtils.exists(filePath)
|
|
245
|
+
? res.sendFile(filePath)
|
|
246
|
+
: next(App.instance.errors.NOT_FOUND.setData({ type: 'file', id: filePath }))
|
|
225
247
|
} catch (e) {
|
|
226
|
-
if (e.code === 'ENOENT') return next(
|
|
227
|
-
return next(e)
|
|
248
|
+
if (e.code === 'ENOENT') return next(e)
|
|
228
249
|
}
|
|
229
250
|
}
|
|
230
251
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-adaptframework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Adapt framework integration for the Adapt authoring tool",
|
|
5
5
|
"homepage": "https://github.com/adapt-security/adapt-authoring-adaptframework",
|
|
6
6
|
"license": "GPL-3.0",
|