qti 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
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