@instructure/quiz-core 21.0.2 → 21.1.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.
Files changed (45) hide show
  1. package/es/building/components/layout/header/BuildingButtons/theme.js +1 -1
  2. package/es/common/actions/taking.js +3 -2
  3. package/es/common/components/layout/navbar/theme.js +1 -1
  4. package/es/common/components/resources/stimulus/StimulusEditInfo/index.js +5 -1
  5. package/es/common/components/resources/stimulus/StimulusEditInfo/presenter.js +15 -2
  6. package/es/common/components/resources/stimulus/StimulusShow/index.js +1 -1
  7. package/es/common/components/shared/Card/CardWrapper/theme.js +1 -1
  8. package/es/common/reducers/taking.js +5 -1
  9. package/es/common/selectors/taking.js +3 -0
  10. package/es/common/util/getClientIpAddress.js +35 -0
  11. package/es/common/util/serializeEvent.js +4 -2
  12. package/es/index.js +2 -3
  13. package/es/moderating/components/events/Event.js +27 -10
  14. package/es/moderating/components/events/ResponseEvent.js +24 -7
  15. package/es/moderating/components/events/SessionStartEvent.js +16 -15
  16. package/es/moderating/components/events/SessionSubmitEvent.js +42 -0
  17. package/es/moderating/components/resources/EventDetails.js +43 -0
  18. package/es/moderating/components/resources/SessionBreachAlert.js +10 -0
  19. package/es/moderating/components/resources/util/checkIsBreach.js +28 -0
  20. package/es/moderating/components/resources/util/extractSessionData.js +20 -0
  21. package/es/reporting/components/resources/common/propTypes.js +14 -0
  22. package/es/taking/api/taking.js +26 -3
  23. package/lib/building/components/layout/header/BuildingButtons/theme.js +1 -1
  24. package/lib/common/actions/taking.js +3 -2
  25. package/lib/common/components/layout/navbar/theme.js +1 -1
  26. package/lib/common/components/resources/stimulus/StimulusEditInfo/index.js +5 -1
  27. package/lib/common/components/resources/stimulus/StimulusEditInfo/presenter.js +15 -2
  28. package/lib/common/components/resources/stimulus/StimulusShow/index.js +1 -1
  29. package/lib/common/components/shared/Card/CardWrapper/theme.js +1 -1
  30. package/lib/common/reducers/taking.js +5 -1
  31. package/lib/common/selectors/taking.js +5 -1
  32. package/lib/common/util/getClientIpAddress.js +43 -0
  33. package/lib/common/util/serializeEvent.js +3 -1
  34. package/lib/index.js +15 -0
  35. package/lib/moderating/components/events/Event.js +26 -9
  36. package/lib/moderating/components/events/ResponseEvent.js +25 -7
  37. package/lib/moderating/components/events/SessionStartEvent.js +16 -15
  38. package/lib/moderating/components/events/SessionSubmitEvent.js +52 -0
  39. package/lib/moderating/components/resources/EventDetails.js +51 -0
  40. package/lib/moderating/components/resources/SessionBreachAlert.js +18 -0
  41. package/lib/moderating/components/resources/util/checkIsBreach.js +36 -0
  42. package/lib/moderating/components/resources/util/extractSessionData.js +28 -0
  43. package/lib/reporting/components/resources/common/propTypes.js +18 -2
  44. package/lib/taking/api/taking.js +26 -3
  45. package/package.json +8 -8
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.EventDetails = void 0;
8
+ var _uiTable = require("@instructure/ui-table");
9
+ var _uiText = require("@instructure/ui-text");
10
+ var _uiButtons = require("@instructure/ui-buttons");
11
+ var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
12
+ var _react = _interopRequireDefault(require("react"));
13
+ var _SessionBreachAlert = require("./SessionBreachAlert.js");
14
+ var _uiIcons = require("@instructure/ui-icons");
15
+ var _uiTooltip = require("@instructure/ui-tooltip");
16
+ var _ref2 = /*#__PURE__*/_react.default.createElement(_SessionBreachAlert.SessionBreachAlert, null);
17
+ var EventDetails = function EventDetails(_ref) {
18
+ var currentEventData = _ref.currentEventData,
19
+ validationErrors = _ref.validationErrors,
20
+ _ref$answerValue = _ref.answerValue,
21
+ answerValue = _ref$answerValue === void 0 ? null : _ref$answerValue;
22
+ var eventTimeString = "".concat((0, _formatMessage.default)('Event time'), ": ").concat(currentEventData.eventDate);
23
+ var renderTooltip = function renderTooltip(message) {
24
+ return /*#__PURE__*/_react.default.createElement(_uiTooltip.Tooltip, {
25
+ renderTip: message,
26
+ placement: "end",
27
+ on: ['click', 'hover', 'focus']
28
+ }, /*#__PURE__*/_react.default.createElement(_uiButtons.IconButton, {
29
+ screenReaderLabel: message,
30
+ renderIcon: _uiIcons.IconInfoLine,
31
+ withBackground: false,
32
+ withBorder: false
33
+ }));
34
+ };
35
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, validationErrors.isBreach && _ref2, /*#__PURE__*/_react.default.createElement("h4", null, eventTimeString), /*#__PURE__*/_react.default.createElement(_uiTable.Table, {
36
+ caption: (0, _formatMessage.default)('System details')
37
+ }, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Head, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.ColHeader, {
38
+ id: "system-details-attribute"
39
+ }, (0, _formatMessage.default)('Attribute')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.ColHeader, {
40
+ id: "system-details-value"
41
+ }, (0, _formatMessage.default)('Value')))), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Body, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, (0, _formatMessage.default)('Client IP address')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, /*#__PURE__*/_react.default.createElement(_uiText.Text, {
42
+ color: validationErrors.ipAddress ? 'danger' : 'primary'
43
+ }, currentEventData.ipAddress), validationErrors.ipAddress && renderTooltip(validationErrors.ipAddress))), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, (0, _formatMessage.default)('Browser session ID')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, /*#__PURE__*/_react.default.createElement(_uiText.Text, {
44
+ color: validationErrors.browserSessionID ? 'danger' : 'primary'
45
+ }, currentEventData.browserSessionID), validationErrors.browserSessionID && renderTooltip(validationErrors.browserSessionID))), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, (0, _formatMessage.default)('Browser')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, /*#__PURE__*/_react.default.createElement(_uiText.Text, {
46
+ color: validationErrors.browserString ? 'danger' : 'primary'
47
+ }, currentEventData.browserString), validationErrors.browserString && renderTooltip(validationErrors.browserString))), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, (0, _formatMessage.default)('Operating System')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, /*#__PURE__*/_react.default.createElement(_uiText.Text, {
48
+ color: validationErrors.userPlatform ? 'danger' : 'primary'
49
+ }, currentEventData.userPlatform), validationErrors.userPlatform && renderTooltip(validationErrors.userPlatform))), answerValue && /*#__PURE__*/_react.default.createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, (0, _formatMessage.default)('Answer value')), /*#__PURE__*/_react.default.createElement(_uiTable.Table.Cell, null, answerValue)))));
50
+ };
51
+ exports.EventDetails = EventDetails;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SessionBreachAlert = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _uiAlerts = require("@instructure/ui-alerts");
10
+ var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
11
+ var _ref = /*#__PURE__*/_react.default.createElement("br", null);
12
+ var SessionBreachAlert = function SessionBreachAlert() {
13
+ return /*#__PURE__*/_react.default.createElement(_uiAlerts.Alert, {
14
+ variant: "warning",
15
+ margin: "small"
16
+ }, (0, _formatMessage.default)('Potential breach: This Quiz appears to have been accessed from multiple devices or browsers.'), _ref, (0, _formatMessage.default)('Review the activity log and take appropriate action.'));
17
+ };
18
+ exports.SessionBreachAlert = SessionBreachAlert;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.checkIsBreach = void 0;
8
+ var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
9
+ var checkIsBreach = function checkIsBreach(firstEventData, currentEventData) {
10
+ var result = {
11
+ isBreach: false
12
+ };
13
+ var checks = [{
14
+ key: 'ipAddress',
15
+ message: (0, _formatMessage.default)('Client IP address is different from initial address')
16
+ }, {
17
+ key: 'browserSessionID',
18
+ message: (0, _formatMessage.default)('Browser session ID is different from initial id')
19
+ }, {
20
+ key: 'browserString',
21
+ message: (0, _formatMessage.default)('Browser is different from initial browser')
22
+ }, {
23
+ key: 'userPlatform',
24
+ message: (0, _formatMessage.default)('Operating system is different from initial system')
25
+ }];
26
+ checks.forEach(function (_ref) {
27
+ var key = _ref.key,
28
+ message = _ref.message;
29
+ if (currentEventData[key] !== firstEventData[key]) {
30
+ result.isBreach = true;
31
+ result[key] = message;
32
+ }
33
+ });
34
+ return result;
35
+ };
36
+ exports.checkIsBreach = checkIsBreach;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.extractSessionData = void 0;
8
+ var _platform = _interopRequireDefault(require("platform"));
9
+ var _quizI18n = require("@instructure/quiz-i18n");
10
+ var extractSessionData = function extractSessionData(sourceData) {
11
+ if (!sourceData) return {
12
+ ipAddress: '',
13
+ browserSessionID: '',
14
+ eventDate: '',
15
+ browserString: '',
16
+ userPlatform: ''
17
+ };
18
+ var clientTimestamp = sourceData.getIn(['eventData', 'clientTimestamp']);
19
+ var userPlatform = _platform.default.parse(sourceData.getIn(['eventData', 'userAgent']));
20
+ return {
21
+ ipAddress: sourceData.getIn(['eventData', 'ipAddress']),
22
+ browserSessionID: sourceData.getIn(['eventData', 'browserSessionId']),
23
+ eventDate: clientTimestamp ? (0, _quizI18n.formatDateTimeSeconds)(clientTimestamp) : '',
24
+ browserString: "".concat(userPlatform.name, " ").concat(userPlatform.version),
25
+ userPlatform: userPlatform.os.toString()
26
+ };
27
+ };
28
+ exports.extractSessionData = extractSessionData;
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.afsFlags = exports.itemAnalysisPropType = exports.answerSummaryPropType = exports.numericTypeAnswerSummaryPropType = exports.richFillBlankTypeAnswerSummaryPropType = exports.matchingTypeAnswerSummaryPropType = exports.scoreDistributionType = exports.scoreDistributionTypeAnswerSummaryPropType = exports.choiceTypeAnswerSummaryPropType = exports.choiceTypeObject = exports.onlyAggregatePropType = exports.aggregatePropType = exports.aggregateDetailPropType = exports.studentAnalysesPropType = exports.quizAnalysisPropType = exports.quizAnalysisMetadata = void 0;
7
+ exports.eventDataPropType = exports.sessionValidationErrorsPropType = exports.afsFlags = exports.itemAnalysisPropType = exports.answerSummaryPropType = exports.numericTypeAnswerSummaryPropType = exports.richFillBlankTypeAnswerSummaryPropType = exports.matchingTypeAnswerSummaryPropType = exports.scoreDistributionType = exports.scoreDistributionTypeAnswerSummaryPropType = exports.choiceTypeAnswerSummaryPropType = exports.choiceTypeObject = exports.onlyAggregatePropType = exports.aggregatePropType = exports.aggregateDetailPropType = exports.studentAnalysesPropType = exports.quizAnalysisPropType = exports.quizAnalysisMetadata = void 0;
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var quizAnalysisMetadata = _propTypes.default.shape({
10
10
  quiz_title: _propTypes.default.string,
@@ -186,4 +186,20 @@ var afsFlags = _propTypes.default.shape({
186
186
  essayEnabled: _propTypes.default.bool.isRequired,
187
187
  fileUploadEnabled: _propTypes.default.bool.isRequired
188
188
  });
189
- exports.afsFlags = afsFlags;
189
+ exports.afsFlags = afsFlags;
190
+ var sessionValidationErrorsPropType = _propTypes.default.shape({
191
+ isBreach: _propTypes.default.bool,
192
+ ipAddress: _propTypes.default.string,
193
+ browserSessionID: _propTypes.default.string,
194
+ browserString: _propTypes.default.string,
195
+ userPlatform: _propTypes.default.string
196
+ });
197
+ exports.sessionValidationErrorsPropType = sessionValidationErrorsPropType;
198
+ var eventDataPropType = _propTypes.default.shape({
199
+ ipAddress: _propTypes.default.string,
200
+ browserSessionID: _propTypes.default.string,
201
+ eventDate: _propTypes.default.string,
202
+ browserString: _propTypes.default.string,
203
+ userPlatform: _propTypes.default.string
204
+ });
205
+ exports.eventDataPropType = eventDataPropType;
@@ -17,6 +17,8 @@ exports.postQuizSession = postQuizSession;
17
17
  exports.getTimeRemaining = getTimeRemaining;
18
18
  exports.recordQuizTime = recordQuizTime;
19
19
  exports.messageForSubmitModal = exports.nextQuestion = exports.submitStudentAccessCode = exports.makeSessionItemCall = exports.getResumeData = void 0;
20
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
21
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
20
22
  var _react = _interopRequireDefault(require("react"));
21
23
  var _partial = _interopRequireDefault(require("lodash/partial"));
22
24
  var _immutable = require("immutable");
@@ -34,6 +36,7 @@ var _quizSessions2 = require("../../common/actions/quizSessions.js");
34
36
  var _callHandlers = require("../../common/api/callHandlers.js");
35
37
  var modalActions = _interopRequireWildcard(require("../../common/actions/modal.js"));
36
38
  var _taking = require("../../common/actions/taking.js");
39
+ var _getClientIpAddress = require("../../common/util/getClientIpAddress.js");
37
40
  // =============================================
38
41
  // =============================================
39
42
 
@@ -167,9 +170,29 @@ function newQuizTakingSession(quizSessionId) {
167
170
  };
168
171
  }
169
172
  function onQuizSessionReadyForTaking(quizSession) {
170
- return function (dispatch) {
171
- dispatch([makeSessionItemCall(quizSession), getResumeData(quizSession.id), (0, _taking.sessionStartOrResumeEvent)(navigator.userAgent), (0, _taking.updateQuizSessionStatusOnPageLoad)(quizSession.status)]);
172
- };
173
+ return /*#__PURE__*/function () {
174
+ var _ref = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee(dispatch) {
175
+ var ipAddress;
176
+ return _regenerator.default.wrap(function _callee$(_context) {
177
+ while (1) {
178
+ switch (_context.prev = _context.next) {
179
+ case 0:
180
+ _context.next = 2;
181
+ return (0, _getClientIpAddress.getClientIpAddress)(quizSession.id);
182
+ case 2:
183
+ ipAddress = _context.sent;
184
+ dispatch([makeSessionItemCall(quizSession), getResumeData(quizSession.id), (0, _taking.sessionStartOrResumeEvent)(navigator.userAgent, ipAddress), (0, _taking.updateQuizSessionStatusOnPageLoad)(quizSession.status)]);
185
+ case 4:
186
+ case "end":
187
+ return _context.stop();
188
+ }
189
+ }
190
+ }, _callee);
191
+ }));
192
+ return function (_x) {
193
+ return _ref.apply(this, arguments);
194
+ };
195
+ }();
173
196
  }
174
197
 
175
198
  // ====================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/quiz-core",
3
- "version": "21.0.2",
3
+ "version": "21.1.1",
4
4
  "license": "MIT",
5
5
  "description": "The Quiz React SDK by Instructure Inc.",
6
6
  "author": "Instructure, Inc. Engineering and Product Design",
@@ -111,12 +111,12 @@
111
111
  "store": "^1.3.20",
112
112
  "striptags": "^2.0.0",
113
113
  "uuid": "^3.2.1",
114
- "@instructure/quiz-common": "21.0.2",
115
- "@instructure/quiz-i18n": "21.0.2",
116
- "@instructure/quiz-interactions": "21.0.2",
117
- "@instructure/quiz-rce": "21.0.2",
118
- "@instructure/quiz-number-input": "21.0.2",
119
- "instructure-validations": "21.0.2"
114
+ "@instructure/quiz-common": "21.1.1",
115
+ "@instructure/quiz-i18n": "21.1.1",
116
+ "@instructure/quiz-number-input": "21.1.1",
117
+ "instructure-validations": "21.1.1",
118
+ "@instructure/quiz-rce": "21.1.1",
119
+ "@instructure/quiz-interactions": "21.1.1"
120
120
  },
121
121
  "devDependencies": {
122
122
  "@instructure/ui-axe-check": "^9.11.1",
@@ -146,7 +146,7 @@
146
146
  "sinon": "^6.1.3",
147
147
  "sinon-chai": "^3.3.0",
148
148
  "@instructure/quiz-scripts": "21.0.0",
149
- "quiz-presets": "21.0.2"
149
+ "quiz-presets": "21.1.1"
150
150
  },
151
151
  "peerDependencies": {
152
152
  "react": "^15 || ^16"