adapt-authoring-adaptframework 2.2.0 → 2.3.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.
|
@@ -804,7 +804,7 @@ class AdaptFrameworkImport {
|
|
|
804
804
|
const schemaName = AdaptFrameworkImport.typeToSchema(data)
|
|
805
805
|
const schema = await this.content.getSchema(schemaName, insertData)
|
|
806
806
|
try {
|
|
807
|
-
this.
|
|
807
|
+
this.resolveAssets(schema, insertData)
|
|
808
808
|
} catch (e) {
|
|
809
809
|
log('error', `failed to extract asset data for attribute '${e.attribute}' of schema '${schemaName}', ${e}`)
|
|
810
810
|
}
|
|
@@ -833,27 +833,16 @@ class AdaptFrameworkImport {
|
|
|
833
833
|
}
|
|
834
834
|
|
|
835
835
|
/**
|
|
836
|
-
*
|
|
837
|
-
* @param {Object} schema Schema for the passed data
|
|
836
|
+
* Replaces asset paths in incoming JSON data with the _id for the corresponding asset, as used internally
|
|
837
|
+
* @param {Object} schema Schema instance for the passed data
|
|
838
838
|
* @param {Object} data Data to check
|
|
839
839
|
*/
|
|
840
|
-
|
|
841
|
-
if (!schema)
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
return
|
|
847
|
-
}
|
|
848
|
-
if (val.properties) {
|
|
849
|
-
this.extractAssets(val.properties, data[key])
|
|
850
|
-
} else if (val?.items?.properties) {
|
|
851
|
-
data[key].forEach(d => this.extractAssets(val.items.properties, d))
|
|
852
|
-
} else if (val?._backboneForms?.type === 'Asset' || val?._backboneForms === 'Asset') {
|
|
853
|
-
data[key] !== ''
|
|
854
|
-
? data[key] = this.assetMap[data[key]] ?? data[key]
|
|
855
|
-
: delete data[key]
|
|
856
|
-
}
|
|
840
|
+
resolveAssets (schema, data) {
|
|
841
|
+
if (!schema) return
|
|
842
|
+
schema.walk(data, field =>
|
|
843
|
+
field?._backboneForms?.type === 'Asset' || field?._backboneForms === 'Asset'
|
|
844
|
+
).forEach(({ data: parent, key, value }) => {
|
|
845
|
+
value ? parent[key] = this.assetMap[value] ?? value : delete parent[key]
|
|
857
846
|
})
|
|
858
847
|
}
|
|
859
848
|
|
|
@@ -52,6 +52,18 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
52
52
|
* @type {Hook}
|
|
53
53
|
*/
|
|
54
54
|
this.postBuildHook = new Hook({ mutable: true })
|
|
55
|
+
/**
|
|
56
|
+
* Middleware hook wrapping the full import lifecycle (pre → import → post).
|
|
57
|
+
* Observers receive (next, importer) and must call next() to proceed.
|
|
58
|
+
* @type {Hook}
|
|
59
|
+
*/
|
|
60
|
+
this.importHook = new Hook({ type: Hook.Types.Middleware })
|
|
61
|
+
/**
|
|
62
|
+
* Middleware hook wrapping the full build lifecycle (pre → build → post).
|
|
63
|
+
* Observers receive (next, builder) and must call next() to proceed.
|
|
64
|
+
* @type {Hook}
|
|
65
|
+
*/
|
|
66
|
+
this.buildHook = new Hook({ type: Hook.Types.Middleware })
|
|
55
67
|
/**
|
|
56
68
|
* Content migration functions to be run on import
|
|
57
69
|
* @type {Array}
|
|
@@ -252,6 +264,9 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
252
264
|
const builder = new AdaptFrameworkBuild(options)
|
|
253
265
|
builder.preBuildHook.tap(() => this.preBuildHook.invoke(builder))
|
|
254
266
|
builder.postBuildHook.tap(() => this.postBuildHook.invoke(builder))
|
|
267
|
+
if (this.buildHook.hasObservers) {
|
|
268
|
+
return this.buildHook.invoke(async () => builder.build(), builder)
|
|
269
|
+
}
|
|
255
270
|
return builder.build()
|
|
256
271
|
}
|
|
257
272
|
|
|
@@ -264,6 +279,9 @@ class AdaptFrameworkModule extends AbstractModule {
|
|
|
264
279
|
const importer = new AdaptFrameworkImport(options)
|
|
265
280
|
importer.preImportHook.tap(() => this.preImportHook.invoke(importer))
|
|
266
281
|
importer.postImportHook.tap(() => this.postImportHook.invoke(importer))
|
|
282
|
+
if (this.importHook.hasObservers) {
|
|
283
|
+
return this.importHook.invoke(async () => importer.import(), importer)
|
|
284
|
+
}
|
|
267
285
|
return importer.import()
|
|
268
286
|
}
|
|
269
287
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-adaptframework",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"adapt-authoring-assets": "^1.4.3",
|
|
34
34
|
"adapt-authoring-auth": "^2.0.0",
|
|
35
|
-
"adapt-authoring-jsonschema": "^1.
|
|
35
|
+
"adapt-authoring-jsonschema": "^1.4.0",
|
|
36
36
|
"adapt-authoring-middleware": "^1.0.1",
|
|
37
37
|
"adapt-authoring-server": "^2.1.0",
|
|
38
38
|
"adapt-authoring-tags": "^1.0.1"
|
|
@@ -148,54 +148,78 @@ describe('AdaptFrameworkImport', () => {
|
|
|
148
148
|
})
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
describe('#
|
|
151
|
+
describe('#resolveAssets()', () => {
|
|
152
152
|
function makeCtx (assetMap) {
|
|
153
153
|
const ctx = { assetMap }
|
|
154
|
-
ctx.
|
|
154
|
+
ctx.resolveAssets = AdaptFrameworkImport.prototype.resolveAssets.bind(ctx)
|
|
155
155
|
return ctx
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function makeSchema (properties) {
|
|
159
|
+
return {
|
|
160
|
+
built: { properties },
|
|
161
|
+
walk (data, predicate, props, parentPath = '') {
|
|
162
|
+
props = props ?? this.built.properties
|
|
163
|
+
const matches = []
|
|
164
|
+
for (const [key, val] of Object.entries(props)) {
|
|
165
|
+
if (data[key] === undefined) continue
|
|
166
|
+
const currentPath = parentPath ? `${parentPath}/${key}` : key
|
|
167
|
+
if (val.properties) {
|
|
168
|
+
matches.push(...this.walk(data[key], predicate, val.properties, currentPath))
|
|
169
|
+
} else if (val?.items?.properties) {
|
|
170
|
+
data[key].forEach((item, i) => {
|
|
171
|
+
matches.push(...this.walk(item, predicate, val.items.properties, `${currentPath}/${i}`))
|
|
172
|
+
})
|
|
173
|
+
} else if (predicate(val)) {
|
|
174
|
+
matches.push({ path: currentPath, key, data, value: data[key] })
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return matches
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
158
182
|
it('should replace asset paths with mapped IDs', () => {
|
|
159
183
|
const ctx = makeCtx({ 'course/en/assets/logo.png': 'asset123' })
|
|
160
|
-
const schema = {
|
|
184
|
+
const schema = makeSchema({
|
|
161
185
|
_graphic: {
|
|
162
186
|
properties: {
|
|
163
187
|
src: { _backboneForms: 'Asset' }
|
|
164
188
|
}
|
|
165
189
|
}
|
|
166
|
-
}
|
|
190
|
+
})
|
|
167
191
|
const data = { _graphic: { src: 'course/en/assets/logo.png' } }
|
|
168
|
-
ctx.
|
|
192
|
+
ctx.resolveAssets(schema, data)
|
|
169
193
|
assert.equal(data._graphic.src, 'asset123')
|
|
170
194
|
})
|
|
171
195
|
|
|
172
196
|
it('should delete empty string asset values', () => {
|
|
173
197
|
const ctx = makeCtx({})
|
|
174
|
-
const schema = {
|
|
198
|
+
const schema = makeSchema({
|
|
175
199
|
_graphic: {
|
|
176
200
|
properties: {
|
|
177
201
|
src: { _backboneForms: 'Asset' }
|
|
178
202
|
}
|
|
179
203
|
}
|
|
180
|
-
}
|
|
204
|
+
})
|
|
181
205
|
const data = { _graphic: { src: '' } }
|
|
182
|
-
ctx.
|
|
206
|
+
ctx.resolveAssets(schema, data)
|
|
183
207
|
assert.equal('src' in data._graphic, false)
|
|
184
208
|
})
|
|
185
209
|
|
|
186
210
|
it('should keep value when not in assetMap', () => {
|
|
187
211
|
const ctx = makeCtx({})
|
|
188
|
-
const schema = {
|
|
212
|
+
const schema = makeSchema({
|
|
189
213
|
img: { _backboneForms: { type: 'Asset' } }
|
|
190
|
-
}
|
|
214
|
+
})
|
|
191
215
|
const data = { img: 'unknown/path.png' }
|
|
192
|
-
ctx.
|
|
216
|
+
ctx.resolveAssets(schema, data)
|
|
193
217
|
assert.equal(data.img, 'unknown/path.png')
|
|
194
218
|
})
|
|
195
219
|
|
|
196
220
|
it('should recurse into nested properties', () => {
|
|
197
221
|
const ctx = makeCtx({ 'assets/bg.jpg': 'asset456' })
|
|
198
|
-
const schema = {
|
|
222
|
+
const schema = makeSchema({
|
|
199
223
|
_settings: {
|
|
200
224
|
properties: {
|
|
201
225
|
_background: {
|
|
@@ -205,15 +229,15 @@ describe('AdaptFrameworkImport', () => {
|
|
|
205
229
|
}
|
|
206
230
|
}
|
|
207
231
|
}
|
|
208
|
-
}
|
|
232
|
+
})
|
|
209
233
|
const data = { _settings: { _background: { src: 'assets/bg.jpg' } } }
|
|
210
|
-
ctx.
|
|
234
|
+
ctx.resolveAssets(schema, data)
|
|
211
235
|
assert.equal(data._settings._background.src, 'asset456')
|
|
212
236
|
})
|
|
213
237
|
|
|
214
238
|
it('should recurse into array items', () => {
|
|
215
239
|
const ctx = makeCtx({ 'assets/a.png': 'id1', 'assets/b.png': 'id2' })
|
|
216
|
-
const schema = {
|
|
240
|
+
const schema = makeSchema({
|
|
217
241
|
_items: {
|
|
218
242
|
items: {
|
|
219
243
|
properties: {
|
|
@@ -221,40 +245,40 @@ describe('AdaptFrameworkImport', () => {
|
|
|
221
245
|
}
|
|
222
246
|
}
|
|
223
247
|
}
|
|
224
|
-
}
|
|
248
|
+
})
|
|
225
249
|
const data = {
|
|
226
250
|
_items: [
|
|
227
251
|
{ src: 'assets/a.png' },
|
|
228
252
|
{ src: 'assets/b.png' }
|
|
229
253
|
]
|
|
230
254
|
}
|
|
231
|
-
ctx.
|
|
255
|
+
ctx.resolveAssets(schema, data)
|
|
232
256
|
assert.equal(data._items[0].src, 'id1')
|
|
233
257
|
assert.equal(data._items[1].src, 'id2')
|
|
234
258
|
})
|
|
235
259
|
|
|
236
260
|
it('should skip undefined data keys', () => {
|
|
237
261
|
const ctx = makeCtx({})
|
|
238
|
-
const schema = {
|
|
262
|
+
const schema = makeSchema({
|
|
239
263
|
_graphic: { _backboneForms: 'Asset' }
|
|
240
|
-
}
|
|
264
|
+
})
|
|
241
265
|
const data = {}
|
|
242
|
-
ctx.
|
|
266
|
+
ctx.resolveAssets(schema, data)
|
|
243
267
|
assert.equal('_graphic' in data, false)
|
|
244
268
|
})
|
|
245
269
|
|
|
246
270
|
it('should handle null schema gracefully', () => {
|
|
247
271
|
const ctx = makeCtx({})
|
|
248
|
-
ctx.
|
|
272
|
+
ctx.resolveAssets(null, { a: 1 })
|
|
249
273
|
})
|
|
250
274
|
|
|
251
275
|
it('should handle _backboneForms as object with type', () => {
|
|
252
276
|
const ctx = makeCtx({ 'path/img.png': 'mapped' })
|
|
253
|
-
const schema = {
|
|
277
|
+
const schema = makeSchema({
|
|
254
278
|
hero: { _backboneForms: { type: 'Asset' } }
|
|
255
|
-
}
|
|
279
|
+
})
|
|
256
280
|
const data = { hero: 'path/img.png' }
|
|
257
|
-
ctx.
|
|
281
|
+
ctx.resolveAssets(schema, data)
|
|
258
282
|
assert.equal(data.hero, 'mapped')
|
|
259
283
|
})
|
|
260
284
|
})
|