Example #1
0
    def test_edxnotes_harvard_notes_enabled(self):
        """
        Tests that edxnotes are disabled when Harvard Annotation Tool is enabled.
        """
        self.course.advanced_modules = ["foo", "imageannotation", "boo"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["foo", "boo", "videoannotation"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["textannotation", "foo", "boo"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["textannotation", "videoannotation", "imageannotation"]
        self.assertFalse(helpers.is_feature_enabled(self.course))
Example #2
0
    def test_edxnotes_harvard_notes_enabled(self):
        """
        Tests that edxnotes are disabled when Harvard Annotation Tool is enabled.
        """
        self.course.advanced_modules = ["foo", "imageannotation", "boo"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["foo", "boo", "videoannotation"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["textannotation", "foo", "boo"]
        self.assertFalse(helpers.is_feature_enabled(self.course))

        self.course.advanced_modules = ["textannotation", "videoannotation", "imageannotation"]
        self.assertFalse(helpers.is_feature_enabled(self.course))
Example #3
0
    def get_html(self, *args, **kwargs):
        """
        Returns raw html for the component.
        """
        is_studio = getattr(self.system, "is_author_mode", False)
        course = self.descriptor.runtime.modulestore.get_course(self.runtime.course_id)

        # Must be disabled:
        # - in Studio;
        # - when Harvard Annotation Tool is enabled for the course;
        # - when the feature flag or `edxnotes` setting of the course is set to False.
        if is_studio or not is_feature_enabled(course):
            return original_get_html(self, *args, **kwargs)
        else:
            return render_to_string("edxnotes_wrapper.html", {
                "content": original_get_html(self, *args, **kwargs),
                "uid": generate_uid(),
                "edxnotes_visibility": json.dumps(
                    getattr(self, 'edxnotes_visibility', course.edxnotes_visibility)
                ),
                "params": {
                    # Use camelCase to name keys.
                    "usageId": unicode(self.scope_ids.usage_id).encode("utf-8"),
                    "courseId": unicode(self.runtime.course_id).encode("utf-8"),
                    "token": get_id_token(self.runtime.get_real_user(self.runtime.anonymous_student_id)),
                    "tokenUrl": get_token_url(self.runtime.course_id),
                    "endpoint": get_endpoint(),
                    "debug": settings.DEBUG,
                    "eventStringLimit": settings.TRACK_MAX_EVENT / 6,
                },
            })
 def test_is_feature_enabled(self, enabled):
     """
     Tests that is_feature_enabled shows correct behavior.
     """
     course = CourseFactory(edxnotes=enabled)
     enrollment = CourseEnrollmentFactory(course_id=course.id)
     assert helpers.is_feature_enabled(course, enrollment.user) == enabled
Example #5
0
def edxnotes(request, course_id):
    """
    Displays the EdxNotes page.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course):
        raise Http404

    try:
        notes = get_notes(request.user, course)
    except EdxNotesServiceUnavailable:
        raise Http404

    context = {
        "course": course,
        "search_endpoint": reverse("search_notes", kwargs={"course_id": course_id}),
        "notes": notes,
        "debug": json.dumps(settings.DEBUG),
        'position': None,
    }

    if not notes:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course.id, request.user, course, depth=2
        )
        course_module = get_module_for_descriptor(request.user, request, course, field_data_cache, course_key)
        position = get_course_position(course_module)
        if position:
            context.update({
                'position': position,
            })

    return render_to_response("edxnotes/edxnotes.html", context)
Example #6
0
def edxnotes_visibility(request, course_id):
    """
    Handle ajax call from "Show notes" checkbox.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    field_data_cache = FieldDataCache([course], course_key, request.user)
    course_module = get_module_for_descriptor(request.user,
                                              request,
                                              course,
                                              field_data_cache,
                                              course_key,
                                              course=course)

    if not is_feature_enabled(course, request.user):
        raise Http404

    try:
        visibility = json.loads(request.body)["visibility"]
        course_module.edxnotes_visibility = visibility
        course_module.save()
        return JsonResponse(status=200)
    except (ValueError, KeyError):
        log.warning(
            "Could not decode request body as JSON and find a boolean visibility field: '%s'",
            request.body)
        return JsonResponseBadRequest()
Example #7
0
 def test_edxnotes_enabled(self):
     """
     Tests that edxnotes are enabled when the course tab configuration contains
     a tab with type "edxnotes."
     """
     self.course.tabs = [{"type": "foo"}, {"name": "Notes", "type": "edxnotes"}, {"type": "bar"}]
     self.assertTrue(helpers.is_feature_enabled(self.course))
Example #8
0
 def test_edxnotes_not_enabled(self):
     """
     Tests that edxnotes are disabled when the course tab configuration does NOT
     contain a tab with type "edxnotes."
     """
     self.course.tabs = []
     self.assertFalse(helpers.is_feature_enabled(self.course))
Example #9
0
 def test_edxnotes_not_enabled(self):
     """
     Tests that edxnotes are disabled when the course tab configuration does NOT
     contain a tab with type "edxnotes."
     """
     self.course.tabs = []
     self.assertFalse(helpers.is_feature_enabled(self.course))
Example #10
0
    def get_html(self, *args, **kwargs):
        """
        Returns raw html for the component.
        """
        # Import is placed here to avoid model import at project startup.
        from edxnotes.helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled
        is_studio = getattr(self.system, "is_author_mode", False)
        course = self.descriptor.runtime.modulestore.get_course(self.runtime.course_id)

        # Must be disabled:
        # - in Studio;
        # - when Harvard Annotation Tool is enabled for the course;
        # - when the feature flag or `edxnotes` setting of the course is set to False.
        if is_studio or not is_feature_enabled(course):
            return original_get_html(self, *args, **kwargs)
        else:
            return render_to_string("edxnotes_wrapper.html", {
                "content": original_get_html(self, *args, **kwargs),
                "uid": generate_uid(),
                "edxnotes_visibility": json.dumps(
                    getattr(self, 'edxnotes_visibility', course.edxnotes_visibility)
                ),
                "params": {
                    # Use camelCase to name keys.
                    "usageId": unicode(self.scope_ids.usage_id).encode("utf-8"),
                    "courseId": unicode(self.runtime.course_id).encode("utf-8"),
                    "token": get_edxnotes_id_token(self.runtime.get_real_user(self.runtime.anonymous_student_id)),
                    "tokenUrl": get_token_url(self.runtime.course_id),
                    "endpoint": get_public_endpoint(),
                    "debug": settings.DEBUG,
                    "eventStringLimit": settings.TRACK_MAX_EVENT / 6,
                },
            })
Example #11
0
 def notes(self):
     """
     Return whether edxnotes is enabled and visible.
     """
     return {
         'enabled': is_feature_enabled(self.overview, self.effective_user),
         'visible': self.overview.edxnotes_visibility,
     }
Example #12
0
 def get_notes(self, course_overview):
     """
     Return whether edxnotes is enabled and visible.
     """
     return {
         'enabled': is_feature_enabled(course_overview, course_overview.effective_user),
         'visible': course_overview.edxnotes_visibility,
     }
Example #13
0
 def test_edxnotes_enabled(self):
     """
     Tests that edxnotes are enabled when the course tab configuration contains
     a tab with type "edxnotes."
     """
     self.course.tabs = [{"type": "foo"},
                         {"name": "Notes", "type": "edxnotes"},
                         {"type": "bar"}]
     self.assertTrue(helpers.is_feature_enabled(self.course))
Example #14
0
    def get_html(self, *args, **kwargs):
        """
        Returns raw html for the component.
        """
        # Import is placed here to avoid model import at project startup.
        from edxnotes.helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled
        is_studio = getattr(self.system, "is_author_mode", False)
        course = getattr(self, 'descriptor',
                         self).runtime.modulestore.get_course(
                             self.runtime.course_id)

        # Must be disabled when:
        # - in Studio
        # - Harvard Annotation Tool is enabled for the course
        # - the feature flag or `edxnotes` setting of the course is set to False
        # - the user is not authenticated
        user = self.runtime.get_real_user(self.runtime.anonymous_student_id)

        if is_studio or not is_feature_enabled(course, user):
            return original_get_html(self, *args, **kwargs)
        else:
            return render_to_string(
                "edxnotes_wrapper.html",
                {
                    "content":
                    original_get_html(self, *args, **kwargs),
                    "uid":
                    generate_uid(),
                    "edxnotes_visibility":
                    json.dumps(
                        getattr(self, 'edxnotes_visibility',
                                course.edxnotes_visibility)),
                    "params": {
                        # Use camelCase to name keys.
                        "usageId":
                        six.text_type(self.scope_ids.usage_id).encode("utf-8"),
                        "courseId":
                        six.text_type(self.runtime.course_id).encode("utf-8"),
                        "token":
                        get_edxnotes_id_token(user),
                        "tokenUrl":
                        get_token_url(self.runtime.course_id),
                        "endpoint":
                        get_public_endpoint(),
                        "debug":
                        settings.DEBUG,
                        "eventStringLimit":
                        settings.TRACK_MAX_EVENT / 6,
                    },
                })
Example #15
0
def edxnotes(request, course_id):
    """
    Displays the EdxNotes page.

    Arguments:
        request: HTTP request object
        course_id: course id

    Returns:
        Rendered HTTP response.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course, request.user):
        raise Http404

    notes_info = get_notes(request, course)
    has_notes = (len(notes_info.get('results')) > 0)
    context = {
        "course": course,
        "notes_endpoint": reverse("notes", kwargs={"course_id": course_id}),
        "notes": notes_info,
        "page_size": DEFAULT_PAGE_SIZE,
        "debug": settings.DEBUG,
        'position': None,
        'disabled_tabs': settings.NOTES_DISABLED_TABS,
        'has_notes': has_notes,
    }

    if not has_notes:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course.id, request.user, course, depth=2)
        course_module = get_module_for_descriptor(request.user,
                                                  request,
                                                  course,
                                                  field_data_cache,
                                                  course_key,
                                                  course=course)
        position = get_course_position(course_module)
        if position:
            context.update({
                'position': position,
            })

    return render_to_response("edxnotes/edxnotes.html", context)
Example #16
0
def edxnotes(request, course_id):
    """
    Displays the EdxNotes page.

    Arguments:
        request: HTTP request object
        course_id: course id

    Returns:
        Rendered HTTP response.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course, request.user):
        raise Http404

    notes_info = get_notes(request, course)
    has_notes = (len(notes_info.get('results')) > 0)
    context = {
        "course": course,
        "notes_endpoint": reverse("notes", kwargs={"course_id": course_id}),
        "notes": notes_info,
        "page_size": DEFAULT_PAGE_SIZE,
        "debug": settings.DEBUG,
        'position': None,
        'disabled_tabs': settings.NOTES_DISABLED_TABS,
        'has_notes': has_notes,
    }

    if not has_notes:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course.id, request.user, course, depth=2
        )
        course_module = get_module_for_descriptor(
            request.user, request, course, field_data_cache, course_key, course=course
        )
        position = get_course_position(course_module)
        if position:
            context.update({
                'position': position,
            })

    return render_to_response("edxnotes/edxnotes.html", context)
Example #17
0
def search_notes(request, course_id):
    """
    Handles search requests.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course):
        raise Http404

    if "text" not in request.GET:
        return HttpResponseBadRequest()

    query_string = request.GET["text"]
    try:
        search_results = search(request.user, course, query_string)
    except (EdxNotesParseError, EdxNotesServiceUnavailable) as err:
        return JsonResponseBadRequest({"error": err.message}, status=500)

    return HttpResponse(search_results)
Example #18
0
def search_notes(request, course_id):
    """
    Handles search requests.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course):
        raise Http404

    if "text" not in request.GET:
        return HttpResponseBadRequest()

    query_string = request.GET["text"]
    try:
        search_results = search(request.user, course, query_string)
    except (EdxNotesParseError, EdxNotesServiceUnavailable) as err:
        return JsonResponseBadRequest({"error": err.message}, status=500)

    return HttpResponse(search_results)
Example #19
0
def edxnotes_visibility(request, course_id):
    """
    Handle ajax call from "Show notes" checkbox.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    field_data_cache = FieldDataCache([course], course_key, request.user)
    course_module = get_module_for_descriptor(
        request.user, request, course, field_data_cache, course_key, course=course
    )

    if not is_feature_enabled(course):
        raise Http404

    try:
        visibility = json.loads(request.body)["visibility"]
        course_module.edxnotes_visibility = visibility
        course_module.save()
        return JsonResponse(status=200)
    except (ValueError, KeyError):
        log.warning("Could not decode request body as JSON and find a boolean visibility field: '%s'", request.body)
        return JsonResponseBadRequest()
Example #20
0
 def test_is_feature_enabled(self, _edxnotes):
     """
     Tests that is_feature_enabled shows correct behavior.
     """
     self.course.edxnotes = _edxnotes
     self.assertEqual(helpers.is_feature_enabled(self.course), _edxnotes)
Example #21
0
def notes(request, course_id):
    """
    Notes view to handle list and search requests.

    Query parameters:
        page: page number to get
        page_size: number of items in the page
        text: text string to search. If `text` param is missing then get all the
              notes for the current user for this course else get only those notes
              which contain the `text` value.

    Arguments:
        request: HTTP request object
        course_id: course id

    Returns:
        Paginated response as JSON. A sample response is below.
        {
          "count": 101,
          "num_pages": 11,
          "current_page": 1,
          "results": [
            {
              "chapter": {
                "index": 4,
                "display_name": "About Exams and Certificates",
                "location": "i4x://org/course/category/name@revision",
                "children": [
                  "i4x://org/course/category/name@revision"
                ]
              },
              "updated": "Dec 09, 2015 at 09:31 UTC",
              "tags": ["shadow","oil"],
              "quote": "foo bar baz",
              "section": {
                "display_name": "edX Exams",
                "location": "i4x://org/course/category/name@revision",
                "children": [
                  "i4x://org/course/category/name@revision",
                  "i4x://org/course/category/name@revision",
                ]
              },
              "created": "2015-12-09T09:31:17.338305Z",
              "ranges": [
                {
                  "start": "/div[1]/p[1]",
                  "end": "/div[1]/p[1]",
                  "startOffset": 0,
                  "endOffset": 6
                }
              ],
              "user": "******",
              "text": "first angry height hungry structure",
              "course_id": "edx/DemoX/Demo",
              "id": "1231",
              "unit": {
                "url": "/courses/edx%2FDemoX%2FDemo/courseware/1414ffd5143b4b508f739b563ab468b7/workflow/1",
                "display_name": "EdX Exams",
                "location": "i4x://org/course/category/name@revision"
              },
              "usage_id": "i4x://org/course/category/name@revision"
            } ],
          "next": "http://0.0.0.0:8000/courses/edx%2FDemoX%2FDemo/edxnotes/notes/?page=2&page_size=10",
          "start": 0,
          "previous": null
        }
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course):
        raise Http404

    page = request.GET.get("page") or DEFAULT_PAGE
    page_size = request.GET.get("page_size") or DEFAULT_PAGE_SIZE
    text = request.GET.get("text")

    try:
        notes_info = get_notes(request, course, page=page, page_size=page_size, text=text)
    except (EdxNotesParseError, EdxNotesServiceUnavailable) as err:
        return JsonResponseBadRequest({"error": err.message}, status=500)

    return HttpResponse(json.dumps(notes_info, cls=NoteJSONEncoder), content_type="application/json")
Example #22
0
def notes(request, course_id):
    """
    Notes view to handle list and search requests.

    Query parameters:
        page: page number to get
        page_size: number of items in the page
        text: text string to search. If `text` param is missing then get all the
              notes for the current user for this course else get only those notes
              which contain the `text` value.

    Arguments:
        request: HTTP request object
        course_id: course id

    Returns:
        Paginated response as JSON. A sample response is below.
        {
          "count": 101,
          "num_pages": 11,
          "current_page": 1,
          "results": [
            {
              "chapter": {
                "index": 4,
                "display_name": "About Exams and Certificates",
                "location": "i4x://org/course/category/name@revision",
                "children": [
                  "i4x://org/course/category/name@revision"
                ]
              },
              "updated": "Dec 09, 2015 at 09:31 UTC",
              "tags": ["shadow","oil"],
              "quote": "foo bar baz",
              "section": {
                "display_name": "edX Exams",
                "location": "i4x://org/course/category/name@revision",
                "children": [
                  "i4x://org/course/category/name@revision",
                  "i4x://org/course/category/name@revision",
                ]
              },
              "created": "2015-12-09T09:31:17.338305Z",
              "ranges": [
                {
                  "start": "/div[1]/p[1]",
                  "end": "/div[1]/p[1]",
                  "startOffset": 0,
                  "endOffset": 6
                }
              ],
              "user": "******",
              "text": "first angry height hungry structure",
              "course_id": "edx/DemoX/Demo",
              "id": "1231",
              "unit": {
                "url": "/courses/edx%2FDemoX%2FDemo/courseware/1414ffd5143b4b508f739b563ab468b7/workflow/1",
                "display_name": "EdX Exams",
                "location": "i4x://org/course/category/name@revision"
              },
              "usage_id": "i4x://org/course/category/name@revision"
            } ],
          "next": "http://0.0.0.0:8000/courses/edx%2FDemoX%2FDemo/edxnotes/notes/?page=2&page_size=10",
          "start": 0,
          "previous": null
        }
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)

    if not is_feature_enabled(course, request.user):
        raise Http404

    page = request.GET.get('page') or DEFAULT_PAGE
    page_size = request.GET.get('page_size') or DEFAULT_PAGE_SIZE
    text = request.GET.get('text')

    try:
        notes_info = get_notes(request,
                               course,
                               page=page,
                               page_size=page_size,
                               text=text)
    except (EdxNotesParseError, EdxNotesServiceUnavailable) as err:
        return JsonResponseBadRequest({"error": text_type(err)}, status=500)

    return HttpResponse(json.dumps(notes_info, cls=NoteJSONEncoder),
                        content_type="application/json")
Example #23
0
 def test_is_feature_enabled(self, _edxnotes):
     """
     Tests that is_feature_enabled shows correct behavior.
     """
     self.course.edxnotes = _edxnotes
     self.assertEqual(helpers.is_feature_enabled(self.course), _edxnotes)
 def test_edxnotes_harvard_notes_enabled(self):
     """
     Tests that edxnotes are disabled when Harvard Annotation Tool is enabled.
     """
     self.course.advanced_modules = ['imageannotation', 'textannotation', 'videoannotation']
     assert not helpers.is_feature_enabled(self.course, self.user)