Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
b0956516
Commit
b0956516
authored
Mar 01, 2016
by
muzaffaryousaf
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Escape html/js with other bug fixes .
TNL-4164
parent
78a61c1f
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
95 additions
and
41 deletions
+95
-41
common/test/acceptance/tests/lms/test_lms_edxnotes.py
+52
-2
lms/djangoapps/edxnotes/helpers.py
+1
-1
lms/djangoapps/edxnotes/tests.py
+6
-6
lms/djangoapps/edxnotes/views.py
+6
-4
lms/static/js/dashboard/track_events.js
+4
-6
lms/static/js/edxnotes/models/note.js
+0
-4
lms/static/js/edxnotes/views/note_item.js
+4
-3
lms/static/js/spec/edxnotes/models/note_spec.js
+1
-1
lms/static/sass/course/_student-notes.scss
+11
-4
lms/templates/edxnotes/edxnotes.html
+10
-10
No files found.
common/test/acceptance/tests/lms/test_lms_edxnotes.py
View file @
b0956516
...
@@ -6,14 +6,13 @@ import random
...
@@ -6,14 +6,13 @@ import random
from
uuid
import
uuid4
from
uuid
import
uuid4
from
datetime
import
datetime
from
datetime
import
datetime
from
nose.plugins.attrib
import
attr
from
nose.plugins.attrib
import
attr
from
..helpers
import
UniqueCourseTest
from
..helpers
import
UniqueCourseTest
,
EventsTestMixin
from
...fixtures.course
import
CourseFixture
,
XBlockFixtureDesc
from
...fixtures.course
import
CourseFixture
,
XBlockFixtureDesc
from
...pages.lms.auto_auth
import
AutoAuthPage
from
...pages.lms.auto_auth
import
AutoAuthPage
from
...pages.lms.course_nav
import
CourseNavPage
from
...pages.lms.course_nav
import
CourseNavPage
from
...pages.lms.courseware
import
CoursewarePage
from
...pages.lms.courseware
import
CoursewarePage
from
...pages.lms.edxnotes
import
EdxNotesUnitPage
,
EdxNotesPage
,
EdxNotesPageNoContent
from
...pages.lms.edxnotes
import
EdxNotesUnitPage
,
EdxNotesPage
,
EdxNotesPageNoContent
from
...fixtures.edxnotes
import
EdxNotesFixture
,
Note
,
Range
from
...fixtures.edxnotes
import
EdxNotesFixture
,
Note
,
Range
from
..helpers
import
EventsTestMixin
class
EdxNotesTestMixin
(
UniqueCourseTest
):
class
EdxNotesTestMixin
(
UniqueCourseTest
):
...
@@ -536,6 +535,57 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
...
@@ -536,6 +535,57 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
"You have not made any notes in this course yet. Other students in this course are using notes to:"
,
"You have not made any notes in this course yet. Other students in this course are using notes to:"
,
notes_page_empty
.
no_content_text
)
notes_page_empty
.
no_content_text
)
def
test_notes_works_correctly_with_xss
(
self
):
"""
Scenario: Note text & tags should be HTML and JS escaped
Given I am enrolled in a course with notes enabled
When I visit the Notes page, with a Notes text and tag containing HTML characters like < and >
Then the text and tags appear as expected due to having been properly escaped
"""
xblocks
=
self
.
course_fixture
.
get_nested_xblocks
(
category
=
"html"
)
self
.
_add_notes
([
Note
(
usage_id
=
xblocks
[
0
]
.
locator
,
user
=
self
.
username
,
course_id
=
self
.
course_fixture
.
_course_key
,
# pylint: disable=protected-access
text
=
'<script>alert("XSS")</script>'
,
quote
=
"quote"
,
updated
=
datetime
(
2014
,
1
,
1
,
1
,
1
,
1
,
1
)
.
isoformat
(),
tags
=
[
'<script>alert("XSS")</script>'
]
),
Note
(
usage_id
=
xblocks
[
1
]
.
locator
,
user
=
self
.
username
,
course_id
=
self
.
course_fixture
.
_course_key
,
# pylint: disable=protected-access
text
=
'<b>bold</b>'
,
quote
=
"quote"
,
updated
=
datetime
(
2014
,
2
,
1
,
1
,
1
,
1
,
1
)
.
isoformat
(),
tags
=
[
'<i>bold</i>'
]
)
])
self
.
notes_page
.
visit
()
notes
=
self
.
notes_page
.
notes
self
.
assertEqual
(
len
(
notes
),
2
)
self
.
assertNoteContent
(
notes
[
0
],
quote
=
u"quote"
,
text
=
'<b>bold</b>'
,
unit_name
=
"Test Unit 1"
,
time_updated
=
"Feb 01, 2014 at 01:01 UTC"
,
tags
=
[
'<i>bold</i>'
]
)
self
.
assertNoteContent
(
notes
[
1
],
quote
=
u"quote"
,
text
=
'<script>alert("XSS")</script>'
,
unit_name
=
"Test Unit 1"
,
time_updated
=
"Jan 01, 2014 at 01:01 UTC"
,
tags
=
[
'<script>alert("XSS")</script>'
]
)
def
test_recent_activity_view
(
self
):
def
test_recent_activity_view
(
self
):
"""
"""
Scenario: User can view all notes by recent activity.
Scenario: User can view all notes by recent activity.
...
...
lms/djangoapps/edxnotes/helpers.py
View file @
b0956516
...
@@ -344,7 +344,7 @@ def get_notes(request, course, page=DEFAULT_PAGE, page_size=DEFAULT_PAGE_SIZE, t
...
@@ -344,7 +344,7 @@ def get_notes(request, course, page=DEFAULT_PAGE, page_size=DEFAULT_PAGE_SIZE, t
collection
[
'previous'
]
collection
[
'previous'
]
)
)
return
json
.
dumps
(
collection
,
cls
=
NoteJSONEncoder
)
return
collection
def
get_endpoint
(
api_url
,
path
=
""
):
def
get_endpoint
(
api_url
,
path
=
""
):
...
...
lms/djangoapps/edxnotes/tests.py
View file @
b0956516
...
@@ -387,7 +387,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
...
@@ -387,7 +387,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
},
},
]
]
},
},
json
.
loads
(
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
)
@patch
(
"edxnotes.helpers.requests.get"
,
autospec
=
True
)
@patch
(
"edxnotes.helpers.requests.get"
,
autospec
=
True
)
...
@@ -493,7 +493,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
...
@@ -493,7 +493,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
},
},
]
]
},
},
json
.
loads
(
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
)
@patch
(
"edxnotes.helpers.requests.get"
,
autospec
=
True
)
@patch
(
"edxnotes.helpers.requests.get"
,
autospec
=
True
)
...
@@ -520,7 +520,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
...
@@ -520,7 +520,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
mock_get
.
return_value
.
content
=
json
.
dumps
(
NOTES_API_EMPTY_RESPONSE
)
mock_get
.
return_value
.
content
=
json
.
dumps
(
NOTES_API_EMPTY_RESPONSE
)
self
.
assertItemsEqual
(
self
.
assertItemsEqual
(
NOTES_VIEW_EMPTY_RESPONSE
,
NOTES_VIEW_EMPTY_RESPONSE
,
json
.
loads
(
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
helpers
.
get_notes
(
self
.
request
,
self
.
course
)
)
)
def
test_preprocess_collection_no_item
(
self
):
def
test_preprocess_collection_no_item
(
self
):
...
@@ -989,14 +989,14 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
...
@@ -989,14 +989,14 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
# pylint: disable=unused-argument
# pylint: disable=unused-argument
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_EDXNOTES"
:
True
})
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_EDXNOTES"
:
True
})
@patch
(
"edxnotes.views.get_notes"
,
return_value
=
json
.
dumps
({
'results'
:
[]})
)
@patch
(
"edxnotes.views.get_notes"
,
return_value
=
{
'results'
:
[]}
)
def
test_edxnotes_view_is_enabled
(
self
,
mock_get_notes
):
def
test_edxnotes_view_is_enabled
(
self
,
mock_get_notes
):
"""
"""
Tests that appropriate view is received if EdxNotes feature is enabled.
Tests that appropriate view is received if EdxNotes feature is enabled.
"""
"""
enable_edxnotes_for_the_course
(
self
.
course
,
self
.
user
.
id
)
enable_edxnotes_for_the_course
(
self
.
course
,
self
.
user
.
id
)
response
=
self
.
client
.
get
(
self
.
notes_page_url
)
response
=
self
.
client
.
get
(
self
.
notes_page_url
)
self
.
assertContains
(
response
,
'Highlights and notes you
\'
ve made in course content'
)
self
.
assertContains
(
response
,
'Highlights and notes you
'
ve made in course content'
)
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_EDXNOTES"
:
False
})
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_EDXNOTES"
:
False
})
def
test_edxnotes_view_is_disabled
(
self
):
def
test_edxnotes_view_is_disabled
(
self
):
...
@@ -1012,7 +1012,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
...
@@ -1012,7 +1012,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
"""
"""
Tests that search notes successfully respond if EdxNotes feature is enabled.
Tests that search notes successfully respond if EdxNotes feature is enabled.
"""
"""
mock_search
.
return_value
=
json
.
dumps
(
NOTES_VIEW_EMPTY_RESPONSE
)
mock_search
.
return_value
=
NOTES_VIEW_EMPTY_RESPONSE
enable_edxnotes_for_the_course
(
self
.
course
,
self
.
user
.
id
)
enable_edxnotes_for_the_course
(
self
.
course
,
self
.
user
.
id
)
response
=
self
.
client
.
get
(
self
.
notes_url
,
{
"text"
:
"test"
})
response
=
self
.
client
.
get
(
self
.
notes_url
,
{
"text"
:
"test"
})
self
.
assertEqual
(
json
.
loads
(
response
.
content
),
NOTES_VIEW_EMPTY_RESPONSE
)
self
.
assertEqual
(
json
.
loads
(
response
.
content
),
NOTES_VIEW_EMPTY_RESPONSE
)
...
...
lms/djangoapps/edxnotes/views.py
View file @
b0956516
...
@@ -22,6 +22,7 @@ from edxnotes.helpers import (
...
@@ -22,6 +22,7 @@ from edxnotes.helpers import (
get_course_position
,
get_course_position
,
DEFAULT_PAGE
,
DEFAULT_PAGE
,
DEFAULT_PAGE_SIZE
,
DEFAULT_PAGE_SIZE
,
NoteJSONEncoder
,
)
)
...
@@ -47,18 +48,19 @@ def edxnotes(request, course_id):
...
@@ -47,18 +48,19 @@ def edxnotes(request, course_id):
raise
Http404
raise
Http404
notes_info
=
get_notes
(
request
,
course
)
notes_info
=
get_notes
(
request
,
course
)
has_notes
=
(
len
(
notes_info
.
get
(
'results'
))
>
0
)
context
=
{
context
=
{
"course"
:
course
,
"course"
:
course
,
"notes_endpoint"
:
reverse
(
"notes"
,
kwargs
=
{
"course_id"
:
course_id
}),
"notes_endpoint"
:
reverse
(
"notes"
,
kwargs
=
{
"course_id"
:
course_id
}),
"notes"
:
notes_info
,
"notes"
:
notes_info
,
"page_size"
:
DEFAULT_PAGE_SIZE
,
"page_size"
:
DEFAULT_PAGE_SIZE
,
"debug"
:
json
.
dumps
(
settings
.
DEBUG
)
,
"debug"
:
settings
.
DEBUG
,
'position'
:
None
,
'position'
:
None
,
'disabled_tabs'
:
settings
.
NOTES_DISABLED_TABS
,
'disabled_tabs'
:
settings
.
NOTES_DISABLED_TABS
,
'has_notes'
:
has_notes
,
}
}
if
len
(
json
.
loads
(
notes_info
)[
'results'
])
==
0
:
if
not
has_notes
:
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
course
.
id
,
request
.
user
,
course
,
depth
=
2
course
.
id
,
request
.
user
,
course
,
depth
=
2
)
)
...
@@ -164,7 +166,7 @@ def notes(request, course_id):
...
@@ -164,7 +166,7 @@ def notes(request, course_id):
except
(
EdxNotesParseError
,
EdxNotesServiceUnavailable
)
as
err
:
except
(
EdxNotesParseError
,
EdxNotesServiceUnavailable
)
as
err
:
return
JsonResponseBadRequest
({
"error"
:
err
.
message
},
status
=
500
)
return
JsonResponseBadRequest
({
"error"
:
err
.
message
},
status
=
500
)
return
HttpResponse
(
notes_info
,
content_type
=
"application/json"
)
return
HttpResponse
(
json
.
dumps
(
notes_info
,
cls
=
NoteJSONEncoder
)
,
content_type
=
"application/json"
)
# pylint: disable=unused-argument
# pylint: disable=unused-argument
...
...
lms/static/js/dashboard/track_events.js
View file @
b0956516
...
@@ -34,9 +34,7 @@ var edx = edx || {};
...
@@ -34,9 +34,7 @@ var edx = edx || {};
// Emit an event when the 'course title link' is clicked.
// Emit an event when the 'course title link' is clicked.
edx
.
dashboard
.
trackCourseTitleClicked
=
function
(
$courseTitleLink
,
properties
){
edx
.
dashboard
.
trackCourseTitleClicked
=
function
(
$courseTitleLink
,
properties
){
var
trackProperty
=
properties
||
edx
.
dashboard
.
generateTrackProperties
;
var
trackProperty
=
properties
||
edx
.
dashboard
.
generateTrackProperties
;
if
(
!
window
.
analytics
)
{
return
;
}
window
.
analytics
.
trackLink
(
window
.
analytics
.
trackLink
(
$courseTitleLink
,
$courseTitleLink
,
'edx.bi.dashboard.course_title.clicked'
,
'edx.bi.dashboard.course_title.clicked'
,
...
@@ -105,9 +103,6 @@ var edx = edx || {};
...
@@ -105,9 +103,6 @@ var edx = edx || {};
};
};
edx
.
dashboard
.
xseriesTrackMessages
=
function
()
{
edx
.
dashboard
.
xseriesTrackMessages
=
function
()
{
if
(
!
window
.
analytics
)
{
return
;
}
$
(
'.xseries-action .btn'
).
each
(
function
(
i
,
element
)
{
$
(
'.xseries-action .btn'
).
each
(
function
(
i
,
element
)
{
var
data
=
edx
.
dashboard
.
generateProgramProperties
(
$
(
element
));
var
data
=
edx
.
dashboard
.
generateProgramProperties
(
$
(
element
));
...
@@ -117,6 +112,9 @@ var edx = edx || {};
...
@@ -117,6 +112,9 @@ var edx = edx || {};
};
};
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
if
(
!
window
.
analytics
)
{
return
;
}
edx
.
dashboard
.
trackCourseTitleClicked
(
$
(
'.course-title > a'
));
edx
.
dashboard
.
trackCourseTitleClicked
(
$
(
'.course-title > a'
));
edx
.
dashboard
.
trackCourseImageLinkClicked
(
$
(
'.cover'
));
edx
.
dashboard
.
trackCourseImageLinkClicked
(
$
(
'.cover'
));
edx
.
dashboard
.
trackEnterCourseLinkClicked
(
$
(
'.enter-course'
));
edx
.
dashboard
.
trackEnterCourseLinkClicked
(
$
(
'.enter-course'
));
...
...
lms/static/js/edxnotes/models/note.js
View file @
b0956516
...
@@ -51,10 +51,6 @@ define(['backbone', 'js/edxnotes/utils/utils', 'underscore.string'], function (B
...
@@ -51,10 +51,6 @@ define(['backbone', 'js/edxnotes/utils/utils', 'underscore.string'], function (B
}
}
return
message
;
return
message
;
},
getText
:
function
()
{
return
Utils
.
nl2br
(
this
.
get
(
'text'
));
}
}
});
});
...
...
lms/static/js/edxnotes/views/note_item.js
View file @
b0956516
...
@@ -31,8 +31,7 @@ define([
...
@@ -31,8 +31,7 @@ define([
getContext
:
function
()
{
getContext
:
function
()
{
return
$
.
extend
({},
this
.
model
.
toJSON
(),
{
return
$
.
extend
({},
this
.
model
.
toJSON
(),
{
message
:
this
.
model
.
getQuote
(),
message
:
this
.
model
.
getQuote
()
text
:
this
.
model
.
getText
()
});
});
},
},
...
@@ -60,7 +59,9 @@ define([
...
@@ -60,7 +59,9 @@ define([
tagHandler
:
function
(
event
)
{
tagHandler
:
function
(
event
)
{
event
.
preventDefault
();
event
.
preventDefault
();
this
.
options
.
scrollToTag
(
event
.
currentTarget
.
text
);
if
(
!
_
.
isUndefined
(
this
.
options
.
scrollToTag
))
{
this
.
options
.
scrollToTag
(
event
.
currentTarget
.
text
);
}
},
},
redirectTo
:
function
(
uri
)
{
redirectTo
:
function
(
uri
)
{
...
...
lms/static/js/spec/edxnotes/models/note_spec.js
View file @
b0956516
...
@@ -46,7 +46,7 @@ define([
...
@@ -46,7 +46,7 @@ define([
it
(
'can return appropriate `text`'
,
function
()
{
it
(
'can return appropriate `text`'
,
function
()
{
var
model
=
this
.
collection
.
at
(
0
);
var
model
=
this
.
collection
.
at
(
0
);
expect
(
model
.
get
Text
()).
toBe
(
'text<br> with<br>line<br>breaks <br>
'
);
expect
(
model
.
get
(
'text'
)).
toBe
(
'text
\
n with
\
r
\
nline
\
n
\
rbreaks
\
r
'
);
});
});
});
});
});
});
lms/static/sass/course/_student-notes.scss
View file @
b0956516
...
@@ -189,6 +189,10 @@ $divider-visual-tertiary: ($baseline/20) solid $gray-l4;
...
@@ -189,6 +189,10 @@ $divider-visual-tertiary: ($baseline/20) solid $gray-l4;
background
:
transparent
;
background
:
transparent
;
}
}
.note-comment-p
{
word-wrap
:
break-word
;
}
.note-comment-ul
,
.note-comment-ul
,
.note-comment-ol
{
.note-comment-ol
{
padding
:
auto
;
padding
:
auto
;
...
@@ -233,11 +237,14 @@ $divider-visual-tertiary: ($baseline/20) solid $gray-l4;
...
@@ -233,11 +237,14 @@ $divider-visual-tertiary: ($baseline/20) solid $gray-l4;
color
:
$m-gray-d2
;
color
:
$m-gray-d2
;
}
}
// CASE: tag matches a search query
.reference-meta.reference-tags
.note-highlight
{
background-color
:
$result-highlight-color-base
;
}
.reference-meta.reference-tags
{
word-wrap
:
break-word
;
// CASE: tag matches a search query
.note-highlight
{
background-color
:
$result-highlight-color-base
;
}
}
// Put commas between tags.
// Put commas between tags.
span
.reference-meta.reference-tags
:after
{
span
.reference-meta.reference-tags
:after
{
content
:
","
;
content
:
","
;
...
...
lms/templates/edxnotes/edxnotes.html
View file @
b0956516
<
%
page
expression_filter=
"h"
/>
<
%
inherit
file=
"/main.html"
/>
<
%
inherit
file=
"/main.html"
/>
<
%
namespace
name=
'static'
file=
'/static_content.html'
/>
<
%
namespace
name=
'static'
file=
'/static_content.html'
/>
<
%!
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
from
django
.
utils
.
translation
import
ugettext
as
_
import
json
from
edxnotes
.
helpers
import
NoteJSONEncoder
from
openedx
.
core
.
djangolib
.
js_utils
import
dump_js_escaped_json
,
js_escaped_string
%
>
%
>
<
%
block
name=
"bodyclass"
>
view-student-notes is-in-course course
</
%
block>
<
%
block
name=
"bodyclass"
>
view-student-notes is-in-course course
</
%
block>
...
@@ -12,10 +15,7 @@ import json
...
@@ -12,10 +15,7 @@ import json
</
%
block>
</
%
block>
<
%
include
file=
"/courseware/course_navigation.html"
args=
"active_page='edxnotes'"
/>
<
%
include
file=
"/courseware/course_navigation.html"
args=
"active_page='edxnotes'"
/>
<
%
_notes =
json.loads(notes)
has_notes =
_notes
and
_notes
.
get
('
results
')
%
>
<section
class=
"container"
>
<section
class=
"container"
>
<div
class=
"wrapper-student-notes"
>
<div
class=
"wrapper-student-notes"
>
<div
class=
"student-notes"
>
<div
class=
"student-notes"
>
...
@@ -111,11 +111,11 @@ import json
...
@@ -111,11 +111,11 @@ import json
<
%
block
name=
"js_extra"
>
<
%
block
name=
"js_extra"
>
<
%
static:require_module
module_name=
"js/edxnotes/views/page_factory"
class_name=
"NotesPageFactory"
>
<
%
static:require_module
module_name=
"js/edxnotes/views/page_factory"
class_name=
"NotesPageFactory"
>
NotesPageFactory({
NotesPageFactory({
disabledTabs: ${disabled_tabs},
disabledTabs: ${disabled_tabs
| n, dump_js_escaped_json
},
notes: ${
notes
},
notes: ${
dump_js_escaped_json(notes, NoteJSONEncoder) | n
},
notesEndpoint:
'${notes_endpoint}'
,
notesEndpoint:
${notes_endpoint | n, dump_js_escaped_json}
,
pageSize:
'${page_size}'
,
pageSize:
${page_size | n, dump_js_escaped_json}
,
debugMode: ${debug}
debugMode: ${debug
| n, dump_js_escaped_json
}
});
});
</
%
static:require
_module
>
</
%
static:require
_module
>
</
%
block>
</
%
block>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment