diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/ResourcePanel.vue b/contentcuration/contentcuration/frontend/channelEdit/components/ResourcePanel.vue index 597acad49b..9df7c448f1 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/ResourcePanel.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/ResourcePanel.vue @@ -433,7 +433,7 @@ return ''; } - const masteryModel = this.node.extra_fields.type; + const masteryModel = this.node.extra_fields.mastery_model; if (!masteryModel) { return this.defaultText; } else if (masteryModel === MasteryModelsNames.M_OF_N) { diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue index 5b4430453a..68a851828b 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue @@ -430,7 +430,7 @@ role: generateGetterSetter('role_visibility'), language: generateGetterSetter('language'), mastery_model() { - return this.getExtraFieldsValueFromNodes('type'); + return this.getExtraFieldsValueFromNodes('mastery_model'); }, m() { return this.getExtraFieldsValueFromNodes('m'); @@ -441,7 +441,7 @@ masteryModelItem: { get() { return { - type: this.mastery_model, + mastery_model: this.mastery_model, m: this.m, n: this.n, }; diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/data.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/data.js index 3891cd898c..28b7e68290 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/data.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/data.js @@ -28,7 +28,7 @@ export function generateNode(props = {}) { }); let extra_fields = { - type: 'do_all', + mastery_model: 'do_all', randomize: false, }; diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js index ee02d52914..927f8d04ab 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js @@ -83,7 +83,7 @@ describe.skip('detailsTabView', () => { role: DEFAULT_EXERCISE.role_visibility, randomizeOrder: DEFAULT_EXERCISE.extra_fields.randomize, masteryModel: { - type: DEFAULT_EXERCISE.extra_fields.type, + mastery_model: DEFAULT_EXERCISE.extra_fields.mastery_model, }, copyrightHolder: DEFAULT_EXERCISE.copyright_holder, }); @@ -146,7 +146,7 @@ describe.skip('detailsTabView', () => { }); it('exercise fields should set selected node data extra_fields', () => { wrapper.find({ ref: 'mastery_model' }).vm.$emit('input', { type: 'm_of_n' }); - expect(wrapper.vm.masteryModel.type).toEqual('m_of_n'); + expect(wrapper.vm.masteryModel.mastery_model).toEqual('m_of_n'); }); }); describe('on validation', () => { diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js index e91f2d3d62..951affbca4 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js @@ -241,8 +241,8 @@ function generateContentNodeData({ } if (extra_fields !== NOVALUE) { contentNodeData.extra_fields = contentNodeData.extra_fields || {}; - if (extra_fields.type) { - contentNodeData.extra_fields.type = extra_fields.type; + if (extra_fields.mastery_model) { + contentNodeData.extra_fields.mastery_model = extra_fields.mastery_model; } if (extra_fields.m) { contentNodeData.extra_fields.m = extra_fields.m; diff --git a/contentcuration/contentcuration/frontend/shared/utils/validation.js b/contentcuration/contentcuration/frontend/shared/utils/validation.js index 801f614cd3..3e7a31fee7 100644 --- a/contentcuration/contentcuration/frontend/shared/utils/validation.js +++ b/contentcuration/contentcuration/frontend/shared/utils/validation.js @@ -185,13 +185,13 @@ export function getNodeLicenseDescriptionErrors(node) { export function getNodeMasteryModelErrors(node) { const mastery = _getMasteryModel(node); return getMasteryModelValidators() - .map(validator => validator(mastery && mastery.type)) + .map(validator => validator(mastery && mastery.mastery_model)) .filter(value => value !== true); } export function getNodeMasteryModelMErrors(node) { const mastery = _getMasteryModel(node); - if (!mastery || mastery.type !== MasteryModelsNames.M_OF_N) { + if (!mastery || mastery.mastery_model !== MasteryModelsNames.M_OF_N) { return []; } return getMasteryModelMValidators(mastery.n) @@ -201,7 +201,7 @@ export function getNodeMasteryModelMErrors(node) { export function getNodeMasteryModelNErrors(node) { const mastery = _getMasteryModel(node); - if (!mastery || mastery.type !== MasteryModelsNames.M_OF_N) { + if (!mastery || mastery.mastery_model !== MasteryModelsNames.M_OF_N) { return []; } return getMasteryModelNValidators() diff --git a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js index 3a7437c8ac..b2706bd979 100644 --- a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js +++ b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js @@ -182,7 +182,7 @@ describe('channelEdit utils', () => { }); it('returns no errors when a mastery model specified', () => { - const node = { extra_fields: { type: MasteryModelsNames.DO_ALL } }; + const node = { extra_fields: { mastery_model: MasteryModelsNames.DO_ALL } }; expect(getNodeMasteryModelErrors(node)).toEqual([]); }); }); @@ -190,20 +190,20 @@ describe('channelEdit utils', () => { describe('getNodeMasteryModelMErrors', () => { it(`returns no errors for empty m value when no mastery model is specified`, () => { - const node = { extra_fields: { type: null, m: null } }; + const node = { extra_fields: { mastery_model: null, m: null } }; expect(getNodeMasteryModelMErrors(node)).toEqual([]); }); it(`returns no errors for empty m value for mastery models other than m of n`, () => { - const node = { extra_fields: { type: MasteryModelsNames.DO_ALL, m: null } }; + const node = { extra_fields: { mastery_model: MasteryModelsNames.DO_ALL, m: null } }; expect(getNodeMasteryModelMErrors(node)).toEqual([]); }); describe('for a mastery model m of n', () => { let node; beforeEach(() => { - node = { extra_fields: { type: MasteryModelsNames.M_OF_N } }; + node = { extra_fields: { mastery_model: MasteryModelsNames.M_OF_N } }; }); it('returns errors for empty m value', () => { @@ -255,20 +255,20 @@ describe('channelEdit utils', () => { describe('getNodeMasteryModelNErrors', () => { it(`returns no errors for empty n value when no mastery model is specified`, () => { - const node = { extra_fields: { type: null, n: null } }; + const node = { extra_fields: { mastery_model: null, n: null } }; expect(getNodeMasteryModelNErrors(node)).toEqual([]); }); it(`returns no errors for empty n value for mastery models other than m of n`, () => { - const node = { extra_fields: { type: MasteryModelsNames.DO_ALL, n: null } }; + const node = { extra_fields: { mastery_model: MasteryModelsNames.DO_ALL, n: null } }; expect(getNodeMasteryModelNErrors(node)).toEqual([]); }); describe('for a mastery model m of n', () => { let node; beforeEach(() => { - node = { extra_fields: { type: MasteryModelsNames.M_OF_N } }; + node = { extra_fields: { mastery_model: MasteryModelsNames.M_OF_N } }; }); it('returns errors for empty n value', () => { @@ -348,7 +348,7 @@ describe('channelEdit utils', () => { kind: ContentKindsNames.EXERCISE, license: { id: 8 }, extra_fields: { - type: MasteryModelsNames.DO_ALL, + mastery_model: MasteryModelsNames.DO_ALL, }, }; assessmentItems = [ @@ -571,7 +571,7 @@ describe('channelEdit utils', () => { kind: 'exercise', license: 8, extra_fields: { - type: 'do_all', + mastery_model: 'do_all', }, }, [], @@ -582,7 +582,7 @@ describe('channelEdit utils', () => { kind: 'exercise', license: 8, extra_fields: { - type: 'm_of_n', + mastery_model: 'm_of_n', m: 3, }, }, @@ -599,7 +599,7 @@ describe('channelEdit utils', () => { kind: 'exercise', license: 8, extra_fields: { - type: 'm_of_n', + mastery_model: 'm_of_n', m: 3, n: 2, }, @@ -612,7 +612,7 @@ describe('channelEdit utils', () => { kind: 'exercise', license: 8, extra_fields: { - type: 'm_of_n', + mastery_model: 'm_of_n', m: 2, n: 3, }, diff --git a/contentcuration/contentcuration/frontend/shared/views/MasteryDropdown.vue b/contentcuration/contentcuration/frontend/shared/views/MasteryDropdown.vue index 5bab8f53e4..085ebb789a 100644 --- a/contentcuration/contentcuration/frontend/shared/views/MasteryDropdown.vue +++ b/contentcuration/contentcuration/frontend/shared/views/MasteryDropdown.vue @@ -109,7 +109,12 @@ type: Object, required: false, validator: function(value) { - return !value || !value.type || !value.type.toString() || MasteryModels.has(value.type); + return ( + !value || + !value.mastery_model || + !value.mastery_model.toString() || + MasteryModels.has(value.mastery_model) + ); }, }, placeholder: { @@ -145,10 +150,10 @@ computed: { masteryModel: { get() { - return this.value && this.value.type; + return this.value && this.value.mastery_model; }, - set(type) { - this.handleInput({ type }); + set(mastery_model) { + this.handleInput({ mastery_model }); }, }, mValue: { diff --git a/contentcuration/contentcuration/frontend/shared/views/__tests__/masteryDropdown.spec.js b/contentcuration/contentcuration/frontend/shared/views/__tests__/masteryDropdown.spec.js index 58f860aa23..591678f6e4 100644 --- a/contentcuration/contentcuration/frontend/shared/views/__tests__/masteryDropdown.spec.js +++ b/contentcuration/contentcuration/frontend/shared/views/__tests__/masteryDropdown.spec.js @@ -25,7 +25,7 @@ describe('masteryDropdown', () => { beforeEach(() => { formWrapper = makeWrapper(); wrapper = formWrapper.find(MasteryDropdown); - wrapper.setProps({ value: { type: 'm_of_n' } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n' } }); modelInput = wrapper.find({ ref: 'masteryModel' }).find('input'); wrapper.vm.$nextTick(() => { mInput = wrapper.find({ ref: 'mValue' }).find('input'); @@ -41,7 +41,7 @@ describe('masteryDropdown', () => { }); it('should render according to masteryModel prop', () => { function test(model) { - wrapper.setProps({ value: { type: model } }); + wrapper.setProps({ value: { mastery_model: model } }); expect(wrapper.vm.$refs.masteryModel.value).toEqual(model); expect(wrapper.find({ ref: 'mValue' }).exists()).toBe(model === 'm_of_n'); expect(wrapper.find({ ref: 'nValue' }).exists()).toBe(model === 'm_of_n'); @@ -49,7 +49,7 @@ describe('masteryDropdown', () => { MasteryModels.forEach(test); }); it('should render correct mValue and nValue props', () => { - wrapper.setProps({ value: { type: 'm_of_n', m: 10, n: 20 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 10, n: 20 } }); expect(wrapper.vm.$refs.mValue.value).toEqual(10); expect(wrapper.vm.$refs.nValue.value).toEqual(20); }); @@ -102,7 +102,7 @@ describe('masteryDropdown', () => { expect(wrapper.emitted('input')).toBeFalsy(); modelInput.setValue('do_all'); expect(wrapper.emitted('input')).toBeTruthy(); - expect(wrapper.emitted('input')[0][0].type).toEqual('do_all'); + expect(wrapper.emitted('input')[0][0].mastery_model).toEqual('do_all'); }); it('input should be emitted when mValue is updated', () => { expect(wrapper.emitted('input')).toBeFalsy(); @@ -119,7 +119,7 @@ describe('masteryDropdown', () => { }); describe('validation', () => { it('should flag empty required mastery models', () => { - wrapper.setProps({ value: { type: null } }); + wrapper.setProps({ value: { mastery_model: null } }); formWrapper.vm.validate(); expect( wrapper @@ -166,7 +166,7 @@ describe('masteryDropdown', () => { ).toBe(false); }); it('should flag if m is not a whole number', () => { - wrapper.setProps({ value: { type: 'm_of_n', m: 0.1231, n: 10 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 0.1231, n: 10 } }); formWrapper.vm.validate(); expect( wrapper @@ -174,7 +174,7 @@ describe('masteryDropdown', () => { .find('.error--text') .exists() ).toBe(true); - wrapper.setProps({ value: { type: 'm_of_n', m: 1, n: 10 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 1, n: 10 } }); formWrapper.vm.validate(); expect( wrapper @@ -184,7 +184,7 @@ describe('masteryDropdown', () => { ).toBe(false); }); it('should flag if m < 1', () => { - wrapper.setProps({ value: { type: 'm_of_n', m: 0, n: 10 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 0, n: 10 } }); formWrapper.vm.validate(); expect( wrapper @@ -192,7 +192,7 @@ describe('masteryDropdown', () => { .find('.error--text') .exists() ).toBe(true); - wrapper.setProps({ value: { type: 'm_of_n', m: 1, n: 10 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 1, n: 10 } }); formWrapper.vm.validate(); expect( wrapper @@ -202,7 +202,7 @@ describe('masteryDropdown', () => { ).toBe(false); }); it('should flag if m > n', () => { - wrapper.setProps({ value: { type: 'm_of_n', m: 2, n: 1 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 2, n: 1 } }); formWrapper.vm.validate(); expect( wrapper @@ -210,7 +210,7 @@ describe('masteryDropdown', () => { .find('.error--text') .exists() ).toBe(true); - wrapper.setProps({ value: { type: 'm_of_n', m: 2, n: 2 } }); + wrapper.setProps({ value: { mastery_model: 'm_of_n', m: 2, n: 2 } }); formWrapper.vm.validate(); expect( wrapper diff --git a/contentcuration/contentcuration/utils/db_tools.py b/contentcuration/contentcuration/utils/db_tools.py index d9055359d6..44c1af9265 100644 --- a/contentcuration/contentcuration/utils/db_tools.py +++ b/contentcuration/contentcuration/utils/db_tools.py @@ -152,7 +152,7 @@ def create_topic(title, parent, description=""): def create_exercise(title, parent, license_id, description="", user=None, empty=False, complete=True): mastery_model = { - "type": exercises.M_OF_N, + "mastery_model": exercises.M_OF_N, "randomize": False, "m": 3, "n": 5, diff --git a/contentcuration/contentcuration/viewsets/contentnode.py b/contentcuration/contentcuration/viewsets/contentnode.py index 52fb7362c7..70dc6ba66e 100644 --- a/contentcuration/contentcuration/viewsets/contentnode.py +++ b/contentcuration/contentcuration/viewsets/contentnode.py @@ -192,7 +192,7 @@ def update(self, queryset, all_validated_data): class ExtraFieldsSerializer(JSONFieldDictSerializer): - type = ChoiceField( + mastery_model = ChoiceField( choices=exercises.MASTERY_MODELS, allow_null=True, required=False ) m = IntegerField(allow_null=True, required=False)