adapt-authoring-adaptframework 1.8.2 → 1.9.1

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.
@@ -194,7 +194,11 @@ class AdaptFrameworkBuild {
194
194
 
195
195
  await Promise.all([
196
196
  this.copyAssets(),
197
- this.copySource()
197
+ FWUtils.copyFrameworkSource({
198
+ destDir: this.dir,
199
+ enabledPlugins: this.enabledPlugins.map(p => p.name),
200
+ linkNodeModules: !this.isExport
201
+ })
198
202
  ])
199
203
  await this.preBuildHook.invoke(this)
200
204
 
@@ -393,31 +397,6 @@ class AdaptFrameworkBuild {
393
397
  }
394
398
  }
395
399
 
396
- /**
397
- * Copies the source code needed for this course. Plugin copy works as a whitelist any unknown plugin files aren't included erroneously.
398
- * @return {Promise}
399
- */
400
- async copySource () {
401
- const { path: fwPath } = await App.instance.waitForModule('adaptframework')
402
- const BLACKLIST = ['.git', '.DS_Store', 'thumbs.db', 'node_modules', 'course', 'migrations']
403
- const ENABLED_PLUGINS = this.enabledPlugins.map(p => p.name)
404
- const srcDir = path.join(fwPath, 'src')
405
- await fs.cp(fwPath, this.dir, {
406
- recursive: true,
407
- filter: f => {
408
- f = path.normalize(f)
409
- const [type, name] = path.relative(srcDir, f).split('/')
410
- const isPlugin = f.startsWith(srcDir) && type && type !== 'core' && !!name
411
-
412
- if (isPlugin && !ENABLED_PLUGINS.includes(name)) {
413
- return false
414
- }
415
- return !BLACKLIST.includes(path.basename(f))
416
- }
417
- })
418
- if (!this.isExport) await fs.symlink(`${fwPath}/node_modules`, `${this.dir}/node_modules`, 'junction')
419
- }
420
-
421
400
  /**
422
401
  * Deals with copying all assets used in this course
423
402
  * @return {Promise}
@@ -1,11 +1,11 @@
1
- import { App, Hook } from 'adapt-authoring-core'
1
+ import { App, Hook, Utils } from 'adapt-authoring-core'
2
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
+ import { randomBytes } from 'node:crypto'
6
7
  import semver from 'semver'
7
8
  import { unzip } from 'zipper'
8
-
9
9
  import FWUtils from './AdaptFrameworkUtils.js'
10
10
 
11
11
  import ComponentTransform from './migrations/component.js'
@@ -245,11 +245,10 @@ class AdaptFrameworkImport {
245
245
  */
246
246
  this.jsonschema = jsonschema
247
247
 
248
- FWUtils.log('info', `running with settings ${JSON.stringify(this.settings, null, 2)}`)
249
- FWUtils.log('debug', 'IMPORT_SETTINGS', JSON.stringify(this.settings, null, 2))
250
248
  FWUtils.log('debug', 'IMPORT_USER', this.userId)
249
+ FWUtils.log('debug', 'IMPORT_SETTINGS', JSON.stringify(this.settings, null, 2))
251
250
 
252
- const { isDryRun, importContent, importPlugins } = this.settings
251
+ const { isDryRun, importContent, importPlugins, migrateContent } = this.settings
253
252
  const tasks = [
254
253
  [this.prepare],
255
254
  [this.loadAssetData],
@@ -260,7 +259,7 @@ class AdaptFrameworkImport {
260
259
  [this.importCoursePlugins, isDryRun && importPlugins],
261
260
  [this.importCoursePlugins, !isDryRun && importContent],
262
261
  [this.loadCourseData, isDryRun && importContent],
263
- [this.migrateCourseData, !isDryRun && importContent],
262
+ [this.migrateCourseData, !isDryRun && migrateContent],
264
263
  [this.loadCourseData, !isDryRun && importContent],
265
264
  [this.importCourseData, !isDryRun && importContent],
266
265
  [this.generateSummary]
@@ -476,8 +475,12 @@ class AdaptFrameworkImport {
476
475
  * Run grunt task
477
476
  * @return {Promise}
478
477
  */
479
- async runGruntTask (subTask, { outputDir, captureDir, outputFilePath }) {
480
- const output = await FWUtils.spawnPromise('npx', ['grunt', `migration:${subTask}`, `--outputdir=${outputDir}`, `--capturedir=${captureDir}`])
478
+ async runGruntMigration (subTask, { outputDir, captureDir, outputFilePath }) {
479
+ const output = await Utils.spawn({
480
+ cmd: 'npx',
481
+ args: ['grunt', `migration:${subTask}`, `--outputdir=${outputDir}`, `--capturedir=${captureDir}`],
482
+ cwd: this.frameworkPath ?? this.framework.path
483
+ })
481
484
  if (outputFilePath) await fs.writeFile(outputFilePath, output)
482
485
  }
483
486
 
@@ -489,16 +492,19 @@ class AdaptFrameworkImport {
489
492
  await this.patchThemeName()
490
493
  await this.patchCustomStyle()
491
494
 
495
+ const migrationId = `${this.userId}-${randomBytes(4).toString('hex')}`
496
+
492
497
  const opts = {
493
498
  outputDir: path.relative(this.framework.path, path.resolve(this.coursePath, '..')),
494
- captureDir: path.join(`./${this.userId}-migrations`),
495
- outputFilePath: path.join(this.framework.path, 'migrations', `${this.userId}.txt`)
499
+ captureDir: path.join(`./${migrationId}-migrations`),
500
+ outputFilePath: path.join(this.framework.path, 'migrations', `${migrationId}.txt`)
496
501
  }
502
+ FWUtils.log('debug', 'MIGRATION_ID', migrationId)
497
503
  FWUtils.logDir('captureDir', opts.captureDir)
498
504
  FWUtils.logDir('outputDir', opts.outputDir)
499
505
 
500
- await this.runGruntTask('capture', opts)
501
- await this.runGruntTask('migrate', opts)
506
+ await this.runGruntMigration('capture', opts)
507
+ await this.runGruntMigration('migrate', opts)
502
508
 
503
509
  await fs.rm(path.join(this.framework.path, opts.captureDir), { recursive: true })
504
510
  } catch (error) {
@@ -111,9 +111,7 @@ class AdaptFrameworkModule extends AbstractModule {
111
111
  async installFramework (version, force = false) {
112
112
  this.log('verbose', 'INSTALL')
113
113
  try {
114
- const modsPath = path.resolve(this.path, '..', 'node_modules')
115
114
  try {
116
- await fs.stat(modsPath)
117
115
  await fs.readFile(path.resolve(this.path, 'package.json'))
118
116
  if (!force) {
119
117
  this.log('verbose', 'INSTALL no action, force !== true')
@@ -125,13 +123,6 @@ class AdaptFrameworkModule extends AbstractModule {
125
123
  // if src and node_modules are missing, install required
126
124
  }
127
125
  await this.runCliCommand('installFramework', { version })
128
- // move node_modules into place
129
- this.log('verbose', 'INSTALL node_modules')
130
- try {
131
- await fs.rm(modsPath, { recursive: true })
132
- } catch (e) {}
133
- // move node_modules so it can be shared with all builds
134
- await fs.rename(path.join(this.path, 'node_modules'), modsPath)
135
126
  } catch (e) {
136
127
  this.log('error', `failed to install framework, ${e.message}`)
137
128
  throw this.app.errors.FW_INSTALL_FAILED
@@ -5,7 +5,6 @@ import fs from 'fs/promises'
5
5
  /* eslint-disable import/no-named-default */import { default as fsSync } from 'fs'
6
6
  import path from 'upath'
7
7
  import semver from 'semver'
8
- import { spawn } from 'child_process'
9
8
 
10
9
  /** @ignore */ const buildCache = {}
11
10
 
@@ -194,6 +193,38 @@ class AdaptFrameworkUtils {
194
193
  return `${sanitisedTitle}${buildData.action === 'export' ? '-export' : ''}`
195
194
  }
196
195
 
196
+ /**
197
+ * Copies the framework source directory
198
+ * @param {Object} options
199
+ * @param {String} options.destDir The destination directory path
200
+ * @param {Array<String>} options.enabledPlugins List of plugins to include
201
+ * @param {Boolean} options.copyNodeModules Whether to physically copy node_modules
202
+ * @param {Boolean} options.linkNodeModules Whether to symlink node_modules
203
+ * @return {Promise}
204
+ */
205
+ static async copyFrameworkSource (options) {
206
+ const { path: fwPath } = await App.instance.waitForModule('adaptframework')
207
+ const BLACKLIST = ['.git', '.DS_Store', 'thumbs.db', 'course', 'migrations']
208
+ if (options.copyNodeModules !== true) BLACKLIST.push('node_modules')
209
+
210
+ const srcDir = path.join(fwPath, 'src')
211
+ const enabledPlugins = options.enabledPlugins ?? []
212
+ await fs.cp(fwPath, options.destDir, {
213
+ recursive: true,
214
+ filter: f => {
215
+ f = path.normalize(f)
216
+ const [type, name] = path.relative(srcDir, f).split('/')
217
+ const isPlugin = f.startsWith(srcDir) && type && type !== 'core' && !!name
218
+
219
+ if (isPlugin && !enabledPlugins.includes(name)) {
220
+ return false
221
+ }
222
+ return !BLACKLIST.includes(path.basename(f))
223
+ }
224
+ })
225
+ if (options.linkNodeModules !== false) await fs.symlink(`${fwPath}/node_modules`, `${options.destDir}/node_modules`, 'junction')
226
+ }
227
+
197
228
  /**
198
229
  * Handles GET requests to the API
199
230
  * @param {external:ExpressRequest} req
@@ -361,26 +392,6 @@ class AdaptFrameworkUtils {
361
392
  handler(middleware.zipTypes, { maxFileSize: fw.getConfig('importMaxFileSize'), unzip: true })(req, res, e => e ? reject(e) : resolve())
362
393
  })
363
394
  }
364
-
365
- static async spawnPromise (cmd, args) {
366
- const framework = await App.instance.waitForModule('adaptframework')
367
- return new Promise((resolve, reject) => {
368
- const cwd = framework.path
369
- AdaptFrameworkUtils.log('debug', 'SPAWN', cmd, cwd)
370
- const task = spawn(cmd, args, { cwd })
371
- let output = ''
372
- let error
373
- task.stdout.on('data', data => {
374
- output += data
375
- })
376
- task.on('error', e => {
377
- error = e
378
- })
379
- task.on('close', exitCode => {
380
- exitCode !== 0 ? reject(framework.app.errors.SPAWN.setData({ error })) : resolve(output)
381
- })
382
- })
383
- }
384
395
  }
385
396
 
386
397
  export default AdaptFrameworkUtils
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adapt-authoring-adaptframework",
3
- "version": "1.8.2",
3
+ "version": "1.9.1",
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",