qti 2.10.0 → 2.11.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ae3526adbf70df2b7523f98526a3b9f7afd575ec1787d77cd434857b1e017a9
4
- data.tar.gz: 76a12f92afbeda2ab3da260bc6cb8d5633ea731d38659c924662177fdb81e771
3
+ metadata.gz: 783579cd76121396d891a45730e833ebed9967a7366f75b61c8dca97dd429091
4
+ data.tar.gz: 15193545fbe7b76ae5e66906a1794f19d3b5d175c7719adb8b01b48223ffe1d2
5
5
  SHA512:
6
- metadata.gz: a95ea76601e38f46c327770bea336a02c5762bee4ea88afc41587aea2cfd640de4f9aecdf5f404a724d97f49758a43fc35f8fe281abcf151a3c412581f8d00ac
7
- data.tar.gz: f5be814d3d040ce676fda735fd8f9816f563b89526ac8750ba02061477d07bee26f98b59198290feb569caf391502f1b4ffa51da73e44b79ce17f042ccec7fd9
6
+ metadata.gz: e2a783e103895c2f88d98e7e79c8a8024b1ef8726b7d54a03021213ac5745d6c85f0d5cb822e2034e64812e63ac2b8501067ef584a1167521be89401d08bc4b6
7
+ data.tar.gz: 82a518e1b780ebc9ca5177212bde1108e7980efe4f4bee9473bc753a238268b1f9bfd1ba57bf8341d668faa8ed02166e5566dcfdb61215ddd817c6b8e6d34e05
data/lib/qti/sanitizer.rb CHANGED
@@ -9,26 +9,37 @@ module Qti
9
9
  }.freeze
10
10
 
11
11
  PROTOCOLS = ['http', 'https', :relative].freeze
12
- FILTER_TAGS = %w[iframe object embed].freeze
12
+ FILTER_TAGS = %w[iframe object embed video audio source].freeze
13
+ MEDIA_SRC_ATTR = %w[src data type codebase].freeze
14
+ MEDIA_FMT_ATTR = %w[width height classid].freeze
15
+ MEDIA_ALT_ATTR = %w[title alt allow allowfullscreen].freeze
16
+ MEDIA_EXT_ATTR = %w[data-media-type data-media-id].freeze
17
+ MEDIA_ATTR = [MEDIA_SRC_ATTR, MEDIA_FMT_ATTR, MEDIA_ALT_ATTR, MEDIA_EXT_ATTR].flatten.freeze
13
18
 
14
19
  CONFIG =
15
20
  {
16
- elements: FILTER_TAGS,
21
+ elements: Sanitize::Config::RELAXED[:elements] + FILTER_TAGS,
17
22
  protocols:
18
23
  {
19
24
  'iframe' => { 'src' => PROTOCOLS },
20
25
  'object' => { 'src' => PROTOCOLS, 'data' => PROTOCOLS },
21
- 'embed' => { 'src' => PROTOCOLS }
22
- }.freeze,
26
+ 'embed' => { 'src' => PROTOCOLS },
27
+ 'video' => { 'src' => PROTOCOLS },
28
+ 'audio' => { 'src' => PROTOCOLS },
29
+ 'source' => { 'src' => PROTOCOLS }
30
+ },
23
31
  attributes:
24
32
  {
25
- 'object' => %w[src width height style data type classid codebase],
33
+ 'video' => MEDIA_ATTR,
34
+ 'audio' => MEDIA_ATTR,
35
+ 'source' => MEDIA_ATTR,
36
+ 'object' => MEDIA_ATTR,
26
37
  'embed' => %w[name src type allowfullscreen pluginspage wmode
27
38
  allowscriptaccess width height],
28
39
  'iframe' => %w[src width height name align frameborder scrolling sandbox
29
40
  allowfullscreen webkitallowfullscreen mozallowfullscreen
30
41
  allow] # TODO: remove explicit allow with domain whitelist account setting
31
- }.freeze
42
+ }
32
43
  }.freeze
33
44
 
34
45
  def clean(html)
@@ -86,7 +97,10 @@ module Qti
86
97
  transformers << object_tag_transformer if import_objects
87
98
  transformers << remap_unknown_tags_transformer
88
99
  transformers << method(:convert_canvas_math_images) if Qti.configuration.extract_latex_from_image_tags
89
- Sanitize::Config::RELAXED.merge transformers: transformers
100
+ Sanitize::Config.merge(
101
+ Sanitize::Config.merge(Sanitize::Config::RELAXED, CONFIG),
102
+ transformers: transformers
103
+ )
90
104
  end
91
105
 
92
106
  def remap_href_path(href)
@@ -29,7 +29,7 @@ module Qti
29
29
  def title
30
30
  @title ||= begin
31
31
  QTIV2_TITLE_PATHS.map do |path|
32
- xpath_with_single_check(path)&.content
32
+ @doc.xpath(path).first&.content
33
33
  end.compact.first
34
34
  end || super
35
35
  end
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.10.0'.freeze
2
+ VERSION = '2.11.0'.freeze
3
3
  end
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- Thie example adapted from the PET Handbook, copyright University of Cambridge ESOL Examinations -->
3
+ <assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2"
4
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+ xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2p2.xsd"
6
+ identifier="choice" title="Unattended Luggage" adaptive="false" timeDependent="false">
7
+ <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="identifier">
8
+ <correctResponse>
9
+ <value>ChoiceA</value>
10
+ </correctResponse>
11
+ </responseDeclaration>
12
+ <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float">
13
+ <defaultValue>
14
+ <value>0</value>
15
+ </defaultValue>
16
+ </outcomeDeclaration>
17
+ <itemBody>
18
+ <p>Look at the text in the picture.</p>
19
+ <p>
20
+ <img src="images/sign.png" alt="NEVER LEAVE LUGGAGE UNATTENDED"/>
21
+ </p>
22
+ <choiceInteraction responseIdentifier="RESPONSE" shuffle="false" maxChoices="1">
23
+ <prompt>What does it say?</prompt>
24
+ <simpleChoice identifier="ChoiceA">You must stay with your luggage at all times.</simpleChoice>
25
+ <simpleChoice identifier="ChoiceB">Do not let someone else look after your luggage.</simpleChoice>
26
+ <simpleChoice identifier="ChoiceC">Remember your luggage when you leave.</simpleChoice>
27
+ </choiceInteraction>
28
+ </itemBody>
29
+ <responseProcessing template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/match_correct"/>
30
+ </assessmentItem>
@@ -0,0 +1,101 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--This is a Reload version 1.3 Content Package document-->
3
+ <!--Spawned from the Reload Content Package Generator - http://www.reload.ac.uk-->
4
+ <manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
5
+ xmlns:imsmd="http://ltsc.ieee.org/xsd/LOM"
6
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7
+ xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_metadata_v2p2"
8
+ identifier="MANIFEST-85D76736-6D19-9DC0-7C0B-57C31A9FD390"
9
+ xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/qti/qtiv2p2/qtiv2p2_imscpv1p2_v1p0.xsd
10
+ http://ltsc.ieee.org/xsd/LOM http://www.imsglobal.org/xsd/imsmd_loose_v1p3p2.xsd
11
+ http://www.imsglobal.org/xsd/imsqti_metadata_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_metadata_v2p2.xsd">
12
+ <metadata>
13
+ <schema>QTIv2.2 Package</schema>
14
+ <schemaversion>1.0.0</schemaversion>
15
+ <imsmd:lom>
16
+ <imsmd:general>
17
+ <imsmd:title>
18
+ <imsmd:string>Example Package</imsmd:string>
19
+ </imsmd:title>
20
+ <imsmd:language>en</imsmd:language>
21
+ <imsmd:description>
22
+ <imsmd:string>This is an example Contentpackage containing a
23
+ single QTI v2.2 item</imsmd:string>
24
+ </imsmd:description>
25
+ </imsmd:general>
26
+ <imsmd:lifeCycle>
27
+ <imsmd:version>
28
+ <imsmd:string>2.1</imsmd:string>
29
+ </imsmd:version>
30
+ <imsmd:status>
31
+ <imsmd:source>LOMv1.0</imsmd:source>
32
+ <imsmd:value>Final</imsmd:value>
33
+ </imsmd:status>
34
+ </imsmd:lifeCycle>
35
+ <imsmd:metaMetadata>
36
+ <imsmd:metadataschema>LOMv1.0</imsmd:metadataschema>
37
+ <imsmd:metadataschema>QTIv2.1</imsmd:metadataschema>
38
+ <imsmd:language>en</imsmd:language>
39
+ </imsmd:metaMetadata>
40
+ <imsmd:technical>
41
+ <imsmd:format>text/x-imsqti-item-xml</imsmd:format>
42
+ <imsmd:format>image/png</imsmd:format>
43
+ </imsmd:technical>
44
+ <imsmd:rights>
45
+ <imsmd:description>
46
+ <imsmd:string>(c) 2005, IMS Global Learning Consortium;
47
+ individual questions may have their own copyright statements.</imsmd:string>
48
+ </imsmd:description>
49
+ </imsmd:rights>
50
+ </imsmd:lom>
51
+ </metadata>
52
+ <organizations/>
53
+ <resources>
54
+ <resource identifier="RES-B38DF83F-A291-86DA-4EC3-B2CEBD1515A4" type="imsqti_item_xmlv2p2"
55
+ href="choice.xml">
56
+ <metadata>
57
+ <imsqti:qtiMetadata>
58
+ <imsqti:timeDependent>false</imsqti:timeDependent>
59
+ <imsqti:interactionType>choiceInteraction</imsqti:interactionType>
60
+ <imsqti:feedbackType>none</imsqti:feedbackType>
61
+ <imsqti:solutionAvailable>true</imsqti:solutionAvailable>
62
+ </imsqti:qtiMetadata>
63
+ <imsmd:lom>
64
+ <imsmd:general>
65
+ <imsmd:identifier>
66
+ <imsmd:entry>choice</imsmd:entry>
67
+ </imsmd:identifier>
68
+ <imsmd:title>
69
+ <imsmd:string>Unattended Luggage</imsmd:string>
70
+ </imsmd:title>
71
+ <imsmd:description>
72
+ <imsmd:string>This example illustrates the
73
+ choiceInteraction being used to obtain a single response from the candidate.</imsmd:string>
74
+ </imsmd:description>
75
+ </imsmd:general>
76
+ <imsmd:lifeCycle>
77
+ <imsmd:version>
78
+ <imsmd:string>2.1</imsmd:string>
79
+ </imsmd:version>
80
+ <imsmd:status>
81
+ <imsmd:source>LOMv1.0</imsmd:source>
82
+ <imsmd:value>Final</imsmd:value>
83
+ </imsmd:status>
84
+ </imsmd:lifeCycle>
85
+ <imsmd:technical>
86
+ <imsmd:format>text/x-imsqti-item-xml</imsmd:format>
87
+ <imsmd:format>image/png</imsmd:format>
88
+ </imsmd:technical>
89
+ <imsmd:rights>
90
+ <imsmd:description>
91
+ <imsmd:string>This example has been adapted from the
92
+ PET Handbook, copyright University of Cambridge ESOL Examinations .</imsmd:string>
93
+ </imsmd:description>
94
+ </imsmd:rights>
95
+ </imsmd:lom>
96
+ </metadata>
97
+ <file href="choice.xml"/>
98
+ <file href="images/sign.png"/>
99
+ </resource>
100
+ </resources>
101
+ </manifest>
@@ -0,0 +1,50 @@
1
+ describe Qti::Sanitizer do
2
+ let(:sanitizer) { Qti::Sanitizer.new }
3
+
4
+ describe '#sanitize' do
5
+ it 'keeps media tags' do
6
+ expect(sanitizer.clean('<img>')).to eq('<img>')
7
+ expect(sanitizer.clean('<video>')).to eq('<video></video>')
8
+ expect(sanitizer.clean('<audio>')).to eq('<audio></audio>')
9
+ expect(sanitizer.clean('<object>')).to eq('<object></object>')
10
+ expect(sanitizer.clean('<embed>')).to eq('<embed>')
11
+ end
12
+
13
+ it 'blocks undesirable tags do' do
14
+ expect(sanitizer.clean('<danger>')).to eq('')
15
+ end
16
+
17
+ it 'allows needed media src attributes' do
18
+ html = '<audio src="http://a.url" data="B64" type="media" codebase="???">'
19
+
20
+ expect(sanitizer.clean(html)).to include 'src'
21
+ expect(sanitizer.clean(html)).to include 'data'
22
+ expect(sanitizer.clean(html)).to include 'type'
23
+ expect(sanitizer.clean(html)).to include 'codebase'
24
+ end
25
+
26
+ it 'allows needed media format attributes' do
27
+ html = '<video width="12" height=14 classid="yes">'
28
+
29
+ expect(sanitizer.clean(html)).to include 'width'
30
+ expect(sanitizer.clean(html)).to include 'height'
31
+ expect(sanitizer.clean(html)).to include 'classid'
32
+ end
33
+
34
+ it 'allows needed media extension attributes' do
35
+ html = '<object data-media-type="thing" data-media-id=123456789>'
36
+
37
+ expect(sanitizer.clean(html)).to include 'data-media-type'
38
+ expect(sanitizer.clean(html)).to include 'data-media-id'
39
+ end
40
+
41
+ it 'allows needed media alt attributes' do
42
+ html = '<source title="Title" alt="description" allow="fullscreen" allowfullscreen=1>'
43
+
44
+ expect(sanitizer.clean(html)).to include 'title'
45
+ expect(sanitizer.clean(html)).to include 'alt'
46
+ expect(sanitizer.clean(html)).to include 'allow'
47
+ expect(sanitizer.clean(html)).to include 'allowfullscreen'
48
+ end
49
+ end
50
+ end
@@ -33,6 +33,14 @@ describe Qti::V2::Models::NonAssessmentTest do
33
33
  include_examples 'loading_a_non-assessment'
34
34
  end
35
35
 
36
+ describe 'imsqti_2.2_package' do
37
+ let(:path) { File.join(fixtures_path, 'imsqti_2.2_package', 'imsmanifest.xml') }
38
+ let(:loaded_class) { described_class.from_path!(path) }
39
+ let(:title) { 'Example Package' }
40
+
41
+ include_examples 'loading_a_non-assessment'
42
+ end
43
+
36
44
  # describe '#stimulus_ref' do
37
45
  # it 'should return the stimulus ref if it exists' do
38
46
  # item = loaded_class.assessment_items[1]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qti
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Diaz
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2022-09-09 00:00:00.000000000 Z
15
+ date: 2022-10-19 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: actionview
@@ -54,6 +54,26 @@ dependencies:
54
54
  - - "<"
55
55
  - !ruby/object:Gem::Version
56
56
  version: '6.2'
57
+ - !ruby/object:Gem::Dependency
58
+ name: dry-logic
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: 1.2.0
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.3'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: 1.2.0
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
57
77
  - !ruby/object:Gem::Dependency
58
78
  name: dry-struct
59
79
  requirement: !ruby/object:Gem::Requirement
@@ -366,6 +386,9 @@ files:
366
386
  - spec/fixtures/canvas_cartridge/non_cc_assessments/ib5281f3537a06f58877107a2501a4e2d.xml.qti
367
387
  - spec/fixtures/edge_cases_1.2.xml
368
388
  - spec/fixtures/feedback_quiz_1.2.xml
389
+ - spec/fixtures/imsqti_2.2_package/choice.xml
390
+ - spec/fixtures/imsqti_2.2_package/images/sign.png
391
+ - spec/fixtures/imsqti_2.2_package/imsmanifest.xml
369
392
  - spec/fixtures/interaction_checks_1.2.xml
370
393
  - spec/fixtures/items_1.2/canvas_multiple_dropdown.xml
371
394
  - spec/fixtures/items_1.2/canvas_multiple_dropdowns.xml
@@ -639,6 +662,7 @@ files:
639
662
  - spec/lib/qti/models/manifest_spec.rb
640
663
  - spec/lib/qti/models/metadata_spec.rb
641
664
  - spec/lib/qti/models/resource_spec.rb
665
+ - spec/lib/qti/sanitizer_spec.rb
642
666
  - spec/lib/qti/v1/models/assessment_item_spec.rb
643
667
  - spec/lib/qti/v1/models/assessment_spec.rb
644
668
  - spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb
@@ -719,6 +743,9 @@ test_files:
719
743
  - spec/fixtures/canvas_cartridge/non_cc_assessments/ib5281f3537a06f58877107a2501a4e2d.xml.qti
720
744
  - spec/fixtures/edge_cases_1.2.xml
721
745
  - spec/fixtures/feedback_quiz_1.2.xml
746
+ - spec/fixtures/imsqti_2.2_package/choice.xml
747
+ - spec/fixtures/imsqti_2.2_package/images/sign.png
748
+ - spec/fixtures/imsqti_2.2_package/imsmanifest.xml
722
749
  - spec/fixtures/interaction_checks_1.2.xml
723
750
  - spec/fixtures/items_1.2/canvas_multiple_dropdown.xml
724
751
  - spec/fixtures/items_1.2/canvas_multiple_dropdowns.xml
@@ -992,6 +1019,7 @@ test_files:
992
1019
  - spec/lib/qti/models/manifest_spec.rb
993
1020
  - spec/lib/qti/models/metadata_spec.rb
994
1021
  - spec/lib/qti/models/resource_spec.rb
1022
+ - spec/lib/qti/sanitizer_spec.rb
995
1023
  - spec/lib/qti/v1/models/assessment_item_spec.rb
996
1024
  - spec/lib/qti/v1/models/assessment_spec.rb
997
1025
  - spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb