diff --git a/actions/loadContentModules.js b/actions/loadContentModules.js index 66f3662dc..46139c015 100644 --- a/actions/loadContentModules.js +++ b/actions/loadContentModules.js @@ -10,6 +10,7 @@ import deckContentTypeError from './error/deckContentTypeError'; import slideIdTypeError from './error/slideIdTypeError'; import { AllowedPattern } from './error/util/allowedPattern'; import serviceUnavailable from './error/serviceUnavailable'; +import PermissionsStore from '../stores/PermissionsStore'; const log = require('./log/clog'); @@ -35,6 +36,9 @@ export default function loadContentModules(context, payload, done) { // }, (callback) => { + let editPermission = (context.getStore(PermissionsStore) && context.getStore(PermissionsStore).permissions && (context.getStore(PermissionsStore).permissions.admin || context.getStore(PermissionsStore).permissions.edit)); + + payload.params.nonExamQuestionsOnly = !editPermission; context.executeAction(loadQuestionsCount, payload, callback); }, (callback) => { diff --git a/actions/loadContentQuestions.js b/actions/loadContentQuestions.js index a872e4a7d..b7de4195f 100644 --- a/actions/loadContentQuestions.js +++ b/actions/loadContentQuestions.js @@ -26,15 +26,12 @@ export default function loadContentQuestions(context, payload, done) { if (err) { log.error(context, {filepath: __filename}); context.executeAction(serviceUnavailable, payload, done); - //context.dispatch('LOAD_CONTENT_QUESTIONS_FAILURE', err); } else { context.dispatch('LOAD_CONTENT_QUESTIONS_SUCCESS', res); context.dispatch('UPDATE_MODULE_TYPE_SUCCESS', {moduleType: 'questions'}); } let pageTitle = shortTitle + ' | Content Questions | ' + payload.params.stype + ' | ' + payload.params.sid; - //context.dispatch('UPDATE_PAGE_TITLE', { - // pageTitle: pageTitle - //}); + done(); }); } diff --git a/actions/questions/invertExamListFlag.js b/actions/questions/invertExamListFlag.js new file mode 100644 index 000000000..78331244d --- /dev/null +++ b/actions/questions/invertExamListFlag.js @@ -0,0 +1,7 @@ +const log = require('../log/clog'); + +export default function invertExamListFlag(context, payload, done) { + log.info(context); + context.dispatch('INVERT_EXAM_LIST_FLAG', payload); + done(); +} diff --git a/actions/questions/loadExamQuestions.js b/actions/questions/loadExamQuestions.js new file mode 100644 index 000000000..db8dc377a --- /dev/null +++ b/actions/questions/loadExamQuestions.js @@ -0,0 +1,37 @@ +const log = require('../log/clog'); +import ContentQuestionsStore from '../../stores/ContentQuestionsStore'; +import deckContentTypeError from '../error/deckContentTypeError'; +import serviceUnavailable from '../error/serviceUnavailable'; +import slideIdTypeError from '../error/slideIdTypeError'; +import { AllowedPattern } from '../error/util/allowedPattern'; +export default function loadExamQuestions(context, payload, done) { + log.info(context); + const selector = context.getStore(ContentQuestionsStore).selector; + const sid = (selector.sid) ? selector.sid.split('-')[0] : ''; + if (payload.params.sid.split('-')[0] !== sid || payload.params.stype !== selector.stype) { + + if (!(['deck', 'slide', 'question'].indexOf(payload.params.stype) > -1 || payload.params.stype === undefined)){ + context.executeAction(deckContentTypeError, payload, done); + return; + } + + if (!(AllowedPattern.SLIDE_ID.test(payload.params.sid) || payload.params.sid === undefined)) { + context.executeAction(slideIdTypeError, payload, done); + return; + } + + context.service.read('questions.examlist', payload, {timeout: 20 * 1000}, (err, res) => { + if (err) { + log.error(context, {filepath: __filename}); + context.executeAction(serviceUnavailable, payload, done); + } else { + context.dispatch('LOAD_CONTENT_QUESTIONS_SUCCESS', res); + context.dispatch('UPDATE_MODULE_TYPE_SUCCESS', {moduleType: 'questions'}); + } + + done(); + }); + } else { + done(); + } +} diff --git a/actions/questions/resetExamAnswers.js b/actions/questions/resetExamAnswers.js new file mode 100644 index 000000000..a83dc1889 --- /dev/null +++ b/actions/questions/resetExamAnswers.js @@ -0,0 +1,6 @@ +import log from '../log/clog'; +export default function resetExamAnswers(context, payload, done) { + log.info(context); + context.dispatch('RESET_ANSWERS', payload); + done(); +} diff --git a/actions/questions/selectExamAnswer.js b/actions/questions/selectExamAnswer.js new file mode 100644 index 000000000..6cb57a995 --- /dev/null +++ b/actions/questions/selectExamAnswer.js @@ -0,0 +1,6 @@ +import log from '../log/clog'; +export default function selectExamAnswer(context, payload, done) { + log.info(context); + context.dispatch('QUESTION_ANSWER_SELECTED', payload); + done(); +} diff --git a/actions/questions/showCorrectExamAnswers.js b/actions/questions/showCorrectExamAnswers.js new file mode 100644 index 000000000..4120dae5b --- /dev/null +++ b/actions/questions/showCorrectExamAnswers.js @@ -0,0 +1,6 @@ +import log from '../log/clog'; +export default function showCorrectExamAnswers(context, payload, done) { + log.info(context); + context.dispatch('SHOW_CORRECT_EXAM_ANSWERS', payload); + done(); +} diff --git a/actions/questions/updateExamList.js b/actions/questions/updateExamList.js new file mode 100644 index 000000000..403acd008 --- /dev/null +++ b/actions/questions/updateExamList.js @@ -0,0 +1,17 @@ +const log = require('../log/clog'); +import serviceUnavailable from '../error/serviceUnavailable'; +import ContentQuestionsStore from '../../stores/ContentQuestionsStore'; + +export default function updateExamList(context, payload, done) { + log.info(context, payload); + + context.service.update('questions.updateExamList', {modifiedSelections: payload.modifiedSelections}, {timeout: 20 * 1000}, (err, res) => { + if (err) { + log.error(context, {filepath: __filename}); + context.executeAction(serviceUnavailable, payload, done); + } else { + context.dispatch('UPDATE_QUESTIONS', payload); + } + done(); + }); +} diff --git a/components/Deck/ContentModulesPanel/ContentModulesPanel.js b/components/Deck/ContentModulesPanel/ContentModulesPanel.js index c3c21e097..21835c781 100644 --- a/components/Deck/ContentModulesPanel/ContentModulesPanel.js +++ b/components/Deck/ContentModulesPanel/ContentModulesPanel.js @@ -19,6 +19,7 @@ import DataSourcePanel from './DataSourcePanel/DataSourcePanel'; import TagsPanel from './TagsPanel/TagsPanel'; //import ContributorsPanel from './ContributorsPanel/ContributorsPanel'; import ContentModulesStore from '../../../stores/ContentModulesStore'; +import PermissionsStore from '../../../stores/PermissionsStore'; import { isLocalStorageOn } from '../../../common.js'; import loadCollectionsTab from '../../../actions/collections/loadCollectionsTab'; import CollectionsPanel from './CollectionsPanel/CollectionsPanel'; @@ -78,7 +79,10 @@ class ContentModulesPanel extends React.Component { handleTabClick(type, e) { switch (type) { case 'questions': - this.context.executeAction(loadContentQuestions, {params: this.props.ContentModulesStore.selector}); + let editPermission = (this.props.PermissionsStore && this.props.PermissionsStore.permissions && (this.props.PermissionsStore.permissions.admin || this.props.PermissionsStore.permissions.edit)); + let params = this.props.ContentModulesStore.selector; + this.context.executeAction(loadContentQuestions, {params: params}); + break; case 'datasource': this.context.executeAction(loadDataSources, {params: this.props.ContentModulesStore.selector}); @@ -277,9 +281,10 @@ class ContentModulesPanel extends React.Component { ContentModulesPanel.contextTypes = { executeAction: PropTypes.func.isRequired }; -ContentModulesPanel = connectToStores(ContentModulesPanel, [ContentModulesStore], (context, props) => { +ContentModulesPanel = connectToStores(ContentModulesPanel, [ContentModulesStore, PermissionsStore], (context, props) => { return { - ContentModulesStore: context.getStore(ContentModulesStore).getState() + ContentModulesStore: context.getStore(ContentModulesStore).getState(), + PermissionsStore: context.getStore(PermissionsStore).getState() }; }); export default ContentModulesPanel; diff --git a/components/Deck/ContentModulesPanel/ContentQuestionsPanel/ContentQuestionAdd.js b/components/Deck/ContentModulesPanel/ContentQuestionsPanel/ContentQuestionAdd.js index 5769fe781..b1c76db90 100644 --- a/components/Deck/ContentModulesPanel/ContentQuestionsPanel/ContentQuestionAdd.js +++ b/components/Deck/ContentModulesPanel/ContentQuestionsPanel/ContentQuestionAdd.js @@ -24,6 +24,7 @@ class ContentQuestionAdd extends React.Component { userId: this.props.userId, relatedObjectId: this.props.selector.sid, relatedObject: this.props.selector.stype, + isExamQuestion: false }; this.updateQuestionTitle = this.updateQuestionTitle.bind(this); this.updateQuestionDifficulty = this.updateQuestionDifficulty.bind(this); @@ -39,6 +40,7 @@ class ContentQuestionAdd extends React.Component { this.updateCorrect4 = this.updateCorrect4.bind(this); this.updateExplanation = this.updateExplanation.bind(this); + this.updateIsExamQuestion = this.updateIsExamQuestion.bind(this); this.saveButtonClick = this.saveButtonClick.bind(this); this.cancelButtonClick = this.cancelButtonClick.bind(this); } @@ -132,6 +134,10 @@ class ContentQuestionAdd extends React.Component { updateQuestionDifficulty(e) { this.setState({difficulty: e.target.value}); } + + updateIsExamQuestion(e) { + this.setState({isExamQuestion: e.target.checked}); + } render() { //const numAnswers = this.props.question.answers.length; @@ -139,7 +145,7 @@ class ContentQuestionAdd extends React.Component { width: '680px', }; return ( -