adapt-authoring-adaptframework 1.10.0 → 1.10.2

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.
@@ -138,6 +138,11 @@ class AdaptFrameworkImport {
138
138
  * @type {Object}
139
139
  */
140
140
  this.newContentPlugins = {}
141
+ /**
142
+ * Plugins that were updated during import with their original metadata for rollback
143
+ * @type {Object}
144
+ */
145
+ this.updatedContentPlugins = {}
141
146
  /**
142
147
  * Key/value store mapping old component keys to component names
143
148
  * @type {Object}
@@ -158,6 +163,11 @@ class AdaptFrameworkImport {
158
163
  * @type {String}
159
164
  */
160
165
  this.userId = userId
166
+ /**
167
+ * Array of tag IDs created during import for rollback
168
+ * @type {Array<String>}
169
+ */
170
+ this.newTagIds = []
161
171
  /**
162
172
  * Contains non-fatal infomation messages regarding import status which can be return as response data. Fatal errors are thrown in the usual way.
163
173
  * @type {Object}
@@ -548,6 +558,7 @@ class AdaptFrameworkImport {
548
558
  await Promise.all(Array.from(newTags).map(async n => {
549
559
  const { _id } = await tags.insert({ title: n })
550
560
  existingTagMap[n] = _id.toString()
561
+ this.newTagIds.push(_id.toString())
551
562
  }))
552
563
  // map tags from titles to new _ids
553
564
  this.tags = this.tags.map(t => existingTagMap[t])
@@ -652,6 +663,11 @@ class AdaptFrameworkImport {
652
663
  const errors = []
653
664
  await Promise.all([...pluginsToInstall, ...pluginsToUpdate].map(async p => {
654
665
  try {
666
+ // Store original plugin metadata for updates before overwriting
667
+ const isUpdate = pluginsToUpdate.includes(p)
668
+ if (isUpdate && this.installedPlugins[p]) {
669
+ this.updatedContentPlugins[p] = this.installedPlugins[p]
670
+ }
655
671
  // try and infer a targetAttribute if there isn't one
656
672
  const pluginBowerPath = path.join(this.usedContentPlugins[p].path, 'bower.json')
657
673
  const bowerJson = await FWUtils.readJson(pluginBowerPath)
@@ -661,7 +677,9 @@ class AdaptFrameworkImport {
661
677
  }
662
678
  if (!this.settings.isDryRun) {
663
679
  const [pluginData] = await this.contentplugin.installPlugins([[p, this.usedContentPlugins[p].path]], { strict: true })
664
- this.newContentPlugins[p] = pluginData
680
+ if (!isUpdate) {
681
+ this.newContentPlugins[p] = pluginData
682
+ }
665
683
  }
666
684
  this.statusReport.info.push({ code: 'INSTALL_PLUGIN', data: { name: p, version: bowerJson.version } })
667
685
  } catch (e) {
@@ -840,14 +858,21 @@ class AdaptFrameworkImport {
840
858
  return
841
859
  }
842
860
  try {
843
- const tasks = [
844
- fs.rm(this.path, { recursive: true })
845
- ]
861
+ const tasks = [fs.rm(this.path, { recursive: true })]
846
862
  if (error) {
847
- tasks.push(
848
- Promise.all(Object.values(this.newContentPlugins).map(p => this.contentplugin.uninstallPlugin(p._id))),
849
- Promise.all(Object.values(this.assetMap).map(a => this.assets.delete({ _id: a })))
850
- )
863
+ // Uninstall newly installed plugins
864
+ tasks.push(Promise.all(Object.values(this.newContentPlugins).map(p => this.contentplugin.uninstallPlugin(p._id))))
865
+ // Restore updated plugins to their original versions
866
+ if (Object.keys(this.updatedContentPlugins).length > 0) {
867
+ tasks.push(this.restoreUpdatedPlugins())
868
+ }
869
+ // Delete imported assets
870
+ tasks.push(Promise.all(Object.values(this.assetMap).map(a => this.assets.delete({ _id: a }))))
871
+ // Delete newly created tags
872
+ if (this.newTagIds.length > 0) {
873
+ const tags = await App.instance.waitForModule('tags')
874
+ tasks.push(Promise.all(this.newTagIds.map(id => tags.delete({ _id: id }))))
875
+ }
851
876
  let _courseId
852
877
  try {
853
878
  const { ObjectId } = await App.instance.waitForModule('mongodb')
@@ -863,6 +888,26 @@ class AdaptFrameworkImport {
863
888
  await Promise.allSettled(tasks)
864
889
  } catch (e) {} // ignore any thrown errors
865
890
  }
891
+
892
+ /**
893
+ * Restores plugins that were updated during import to their original versions
894
+ * Uses ContentPluginModule's restorePluginFromBackup to restore from cached backups
895
+ * @return {Promise}
896
+ */
897
+ async restoreUpdatedPlugins () {
898
+ const pluginNames = Object.keys(this.updatedContentPlugins)
899
+ if (pluginNames.length === 0) return Promise.resolve()
900
+
901
+ const restoreTasks = []
902
+ for (const [pluginName, originalMetadata] of Object.entries(this.updatedContentPlugins)) {
903
+ FWUtils.log('info', `restoring plugin '${pluginName}' to previous version ${originalMetadata.version}`)
904
+ restoreTasks.push(
905
+ this.contentplugin.restorePluginFromBackup(pluginName)
906
+ .catch(e => FWUtils.log('error', `failed to restore plugin '${pluginName}' from backup, ${e.message}`))
907
+ )
908
+ }
909
+ return Promise.allSettled(restoreTasks)
910
+ }
866
911
  }
867
912
 
868
913
  export default AdaptFrameworkImport
@@ -1,8 +1,15 @@
1
+ import { App } from 'adapt-authoring-core'
2
+
1
3
  async function ComponentTransform (data, importer) {
2
4
  if (data._type !== 'component') {
3
5
  return
4
6
  }
5
- data._component = importer.componentNameMap[data._component]
7
+ const mapped = importer.componentNameMap[data._component]
8
+ if (mapped) {
9
+ data._component = mapped
10
+ } else if (!await importer.contentplugin.findOne({ name: data._component }, { validate: false })) {
11
+ throw App.instance.errors.FW_IMPORT_INVALID_CONTENT.setData({ item: data._component })
12
+ }
6
13
 
7
14
  if (data._playerOptions === '') {
8
15
  delete data._playerOptions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adapt-authoring-adaptframework",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
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",