Merge pull request #6604 from edx/markhoeber-developer-guide-move
Notice on Developer's Guide move
@@ -6,6 +6,7 @@ The following documentation projects have been moved to the `edx-documentation`_
|
||||
|
||||
* course_authors
|
||||
* data
|
||||
* developers
|
||||
* install_operations
|
||||
* mobile
|
||||
* OLX
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
PAPER ?=
|
||||
BUILDDIR ?= build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
Q_FLAG =
|
||||
|
||||
ifeq ($(quiet), true)
|
||||
Q_FLAG = -Q
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = $(Q_FLAG) -d $(BUILDDIR)/doctrees -c source $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/edX.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/edX.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/edX"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/edX"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
46
docs/en_us/developers/README.rst
Normal file
@@ -0,0 +1,46 @@
|
||||
######################
|
||||
EdX Developer's Guide
|
||||
######################
|
||||
|
||||
We have moved the edX Developer's Guide to the `edx-documentation`_ repository
|
||||
as of January 13, 2015.
|
||||
|
||||
By moving documentation to its own repository, we will be better able to
|
||||
develop workflows, manage versioning, create translations, and automate
|
||||
testing, without complicating ongoing development of the edX Platform.
|
||||
|
||||
.. _edx_documentation: https://github.com/edx/edx-documentation
|
||||
|
||||
******************************
|
||||
EdX Platform Docstrings
|
||||
******************************
|
||||
|
||||
We are in the process of creating a new project to publish docstrings for the
|
||||
edX Platform. Docstrings will be included for CMS, LMS, and Common modules.
|
||||
|
||||
This project will remain in the edX Platform repository, in the docs/en-us
|
||||
directory.
|
||||
|
||||
******************************
|
||||
View Published Documentation
|
||||
******************************
|
||||
|
||||
EdX documentation is published through Read the Docs. Links to all published
|
||||
documentation are available through `docs.edx.org`_.
|
||||
|
||||
.. _docs.edx.org: http://docs.edx.org
|
||||
|
||||
******************************
|
||||
Submit Documentation Issues
|
||||
******************************
|
||||
|
||||
We welcome input from the community on any documentation issues. You can
|
||||
submit issues to the Documentation project in the `Open edX JIRA board`_.
|
||||
|
||||
You will need to `create a free JIRA account`_ account before you can submit your first
|
||||
ticket.
|
||||
|
||||
.. _create a free JIRA account: https://openedx.atlassian.net/admin/users/sign-up
|
||||
.. _Open edX JIRA board: https://openedx.atlassian.net
|
||||
|
||||
You can also email docs@edx.org.
|
||||
@@ -1,7 +0,0 @@
|
||||
path.py
|
||||
Django >=1.4,<1.5
|
||||
pytz
|
||||
-e git+https://github.com/edx/XBlock.git#egg=XBlock
|
||||
lxml
|
||||
sphinxcontrib-napoleon==0.2.6
|
||||
stevedore==0.14.1
|
||||
|
Before Width: | Height: | Size: 157 KiB |
@@ -1,5 +0,0 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block header %}
|
||||
<img src="{{ pathto("_static/homepage-bg.jpg", 1) }}" alt="Edx logo" width="100%;"/>
|
||||
{% endblock %}
|
||||
@@ -1,131 +0,0 @@
|
||||
.. _analytics:
|
||||
|
||||
##############
|
||||
Analytics
|
||||
##############
|
||||
|
||||
The edX LMS and Studio are instrumented to enable tracking of metrics and events of interest. These data can be used for educational research, decision support, and operational monitoring.
|
||||
|
||||
The primary mechanism for tracking events is the `Event Tracking`_ API. It should be used for the vast majority of cases.
|
||||
|
||||
=================
|
||||
Event Tracking
|
||||
=================
|
||||
|
||||
The `event-tracking`_ library aims to provide a simple API for tracking point-in-time events. The `event-tracking documentation`_ summarizes the features and primary use cases of the library as well as the current and future design intent.
|
||||
|
||||
Emitting Events
|
||||
*****************
|
||||
|
||||
Emitting from server-side python code::
|
||||
|
||||
from eventtracking import tracker
|
||||
tracker.emit('some.event.name', {'foo': 'bar'})
|
||||
|
||||
Emitting from client-side coffee script::
|
||||
|
||||
Logger.log 'some.event.name', 'foo': 'bar'
|
||||
|
||||
.. note::
|
||||
The client-side API currently uses a deprecated library (the ``track`` djangoapp) instead of the event-tracking library. Eventually, event-tracking will publish a client-side API of its own: when available, that API should be used instead of the ``track``-based solution. See :ref:`deprecated_api`.
|
||||
|
||||
Naming Events
|
||||
==============
|
||||
|
||||
Event names are intended to be formatted as `.` separated strings and help processing of related events. The structure is intended to be `namespace.object.action`. The namespace is intended to be a `.` separated string that helps identify the source of events and prevent events with similar or identical objects and actions from being confused with one another. The object is intended to be a noun describing the object that was acted on. The action is intended to be a past tense verb describing what happened.
|
||||
|
||||
Examples:
|
||||
|
||||
* ``edx.course.enrollment.activated``
|
||||
* Namespace: ``edx``
|
||||
* Object: ``course.enrollment``
|
||||
* Action: ``activated``
|
||||
|
||||
Choosing Events to Emit
|
||||
========================
|
||||
|
||||
Consider emitting events to capture user intent. These will typically be emitted on the client side when a user
|
||||
interacts with the user interface in some way.
|
||||
|
||||
Consider also emitting events when models change. Most models are not append-only and it is frequently the case that an
|
||||
analyst would want to see the value of a particular field at a particular moment in time. Given that many fields are
|
||||
overwritten, that information is lost unless an event is emitted when the model is changed.
|
||||
|
||||
Sensitive Information
|
||||
=====================
|
||||
|
||||
By default, event information is written to an unencrypted file on disk. Therefore, do not include clear text passwords, credit card numbers, or other similarly sensitive information.
|
||||
|
||||
Size
|
||||
======
|
||||
|
||||
A cursory effort to regulate the size of the event is appreciated. If an event is too large, it may be omitted from the event stream. However, do not sacrifice the clarity of an event in an attempt to minimize size. It is much more important that the event is clear.
|
||||
|
||||
Debugging Events
|
||||
=================
|
||||
|
||||
On devstack, emitted events are stored in the ``/edx/var/log/tracking.log`` log
|
||||
file. This file can be useful for validation and debugging.
|
||||
|
||||
Documenting Events
|
||||
*******************
|
||||
|
||||
The *edX Platform Developer's Guide* provides guidelines for `Contributing to
|
||||
Open edX <http://edx.readthedocs.org/projects/edx-developer-
|
||||
guide/en/latest/process/index.html>`_. As part of your effort to add events to
|
||||
the platform, consider including comments that identify the purpose of the
|
||||
events and the fields emitted for them. A description can assure that
|
||||
researchers and other members of the open edX community understand your intent
|
||||
and use the event correctly.
|
||||
|
||||
The `edX Research Guide
|
||||
<http://edx.readthedocs.org/projects/devdata/en/latest/>`_ includes reference
|
||||
information for emitted events that are included in tracking logs.
|
||||
|
||||
Request Context Middleware
|
||||
**********************************
|
||||
|
||||
The platform includes a middleware class that enriches all events emitted
|
||||
during the processing of a given request with details about the request that
|
||||
greatly simplify downstream processing. This is called the ``TrackMiddleware``
|
||||
and can be found in ``edx-platform/common/djangoapps/track/middleware.py``.
|
||||
|
||||
Legacy Application Event Processor
|
||||
**********************************
|
||||
|
||||
In order to support legacy analysis applications, the platform emits standard events using ``eventtracking.tracker.emit()``. However, it uses a custom event processor which modifies the event before saving it to ensure that the event can be parsed by legacy systems. Specifically, it replicates some information so that it is accessible in exactly the same way as it was before. This state is intended to be temporary until all existing legacy systems can be altered to use the new field locations.
|
||||
|
||||
=======================
|
||||
Other Tracking Systems
|
||||
=======================
|
||||
|
||||
The following tracking systems are currently used for specialized analytics. There is some redundancy with event-tracking that is undesirable. The event-tracking library could be extended to support some of these systems, allowing for a single API to be used while still transmitting data to each of these service providers. This would reduce discrepancies between the measurements made by the various systems and significantly clarify the instrumentation.
|
||||
|
||||
Data Dog
|
||||
*****************
|
||||
|
||||
Data dog is used primarily for real-time operational monitoring of a running edX platform server. It supports rapid display and monitoring of various metrics within the platform such as enrollments, user creation and answers to problems.
|
||||
|
||||
edX platform is instrumented to send data to `data dog`_ using the standard `dogapi`_ python package. If ``lms.auth.json`` contains a ``DATADOG_API`` key whose value is a valid data dog API key, then the edX platform will transmit a variety of metrics to data dog. Running ``git grep dog_stats_api`` will give a pretty good overview of the usage of data dog to track operational metrics.
|
||||
|
||||
Segment.IO
|
||||
*****************
|
||||
|
||||
A selection of events can be transmitted to segment.io in order to take advantage of a wide variety of analytics-related third party services such as Mixpanel and Chartbeat. It is enabled in the LMS if the ``SEGMENT_IO_LMS`` feature flag is enabled and the ``SEGMENT_IO_LMS_KEY`` key is set to a valid segment.io API key in the ``lms.auth.json`` file.
|
||||
|
||||
Google Analytics
|
||||
*****************
|
||||
|
||||
Google analytics tracks all LMS page views. It provides several useful metrics such as common referrers and search terms that users used to find the edX web site.
|
||||
|
||||
.. _deprecated_api:
|
||||
|
||||
Deprecated APIs
|
||||
*****************
|
||||
|
||||
The ``track`` djangoapp contains a deprecated mechanism for emitting events. Direct usage of ``server_track`` is deprecated and should be avoided in new code. Old calls to ``server_track`` should be replaced with calls to ``tracker.emit()``. The celery task-based event emission and client-side event handling do not currently have a suitable alternative approach, so they continue to be supported.
|
||||
|
||||
.. _event-tracking: https://github.com/edx/event-tracking
|
||||
.. _event-tracking documentation: http://event-tracking.readthedocs.org/en/latest/overview.html#event-tracking
|
||||
.. _data dog: http://www.datadoghq.com/
|
||||
.. _dogapi: http://pydoc.datadoghq.com/en/latest/
|
||||
@@ -1 +0,0 @@
|
||||
.. include:: ../../shared/browsers.rst
|
||||
@@ -1,7 +0,0 @@
|
||||
*******************************************
|
||||
Calc
|
||||
*******************************************
|
||||
|
||||
.. automodule:: calc
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,52 +0,0 @@
|
||||
*******************************************
|
||||
Capa module
|
||||
*******************************************
|
||||
Contents:
|
||||
|
||||
.. module:: capa
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
Capa_problem
|
||||
============
|
||||
|
||||
.. automodule:: capa.capa_problem
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Checker
|
||||
=======
|
||||
|
||||
.. automodule:: capa.checker
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Correctmap
|
||||
==========
|
||||
|
||||
.. automodule:: capa.correctmap
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Customrender
|
||||
============
|
||||
|
||||
.. automodule:: capa.customrender
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Inputtypes
|
||||
==========
|
||||
|
||||
.. automodule:: capa.inputtypes
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Resposetypes
|
||||
============
|
||||
|
||||
.. automodule:: capa.responsetypes
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
**********
|
||||
Change Log
|
||||
**********
|
||||
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 75
|
||||
:header-rows: 1
|
||||
|
||||
* - Date
|
||||
- Change
|
||||
* - 11/07/14
|
||||
- Created the :ref:`edX Modulestores` section and added the :ref:`Split
|
||||
Mongo Modulestore` chapter.
|
||||
* - 06/23/14
|
||||
- Added a :ref:`Preface` with resources for course teams, developers, researchers, and students.
|
||||
* - 05/20/14
|
||||
- Added the :ref:`Analytics` chapter.
|
||||
* - 04/25/2014
|
||||
- Added the :ref:`Contributing to Open edX` chapter.
|
||||
* - 03/28/2014
|
||||
- Added the :ref:`Custom JavaScript Applications` chapter.
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
*******************************************
|
||||
Chemistry modules
|
||||
*******************************************
|
||||
|
||||
.. module:: chem
|
||||
|
||||
Miller
|
||||
======
|
||||
|
||||
.. automodule:: chem.miller
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
UI part and inputtypes
|
||||
----------------------
|
||||
Miller module is used in the system in crystallography problems.
|
||||
Crystallography is a class in :mod:`capa` inputtypes module.
|
||||
It uses *crystallography.html* for rendering and **crystallography.js**
|
||||
for UI part.
|
||||
|
||||
Documentation from **crystallography.js**::
|
||||
|
||||
For a crystallographic problem of the type
|
||||
|
||||
Given a plane definition via miller indexes, specify it by plotting points on the edges
|
||||
of a 3D cube. Additionally, select the correct Bravais cubic lattice type depending on the
|
||||
physical crystal mentioned in the problem.
|
||||
|
||||
we create a graph which contains a cube, and a 3D Cartesian coordinate system. The interface
|
||||
will allow to plot 3 points anywhere along the edges of the cube, and select which type of
|
||||
Bravais lattice should be displayed along with the basic cube outline.
|
||||
|
||||
When 3 points are successfully plotted, an intersection of the resulting plane (defined by
|
||||
the 3 plotted points), and the cube, will be automatically displayed for clarity.
|
||||
|
||||
After lotting the three points, it is possible to continue plotting additional points. By
|
||||
doing so, the point that was plotted first (from the three that already exist), will be
|
||||
removed, and the new point will be added. The intersection of the resulting new plane and
|
||||
the cube will be redrawn.
|
||||
|
||||
The UI has been designed in such a way, that the user is able to determine which point will
|
||||
be removed next (if adding a new point). This is achieved via filling the to-be-removed point
|
||||
with a different color.
|
||||
|
||||
|
||||
|
||||
Chemcalc
|
||||
========
|
||||
|
||||
.. automodule:: chem.chemcalc
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Chemtools
|
||||
=========
|
||||
|
||||
.. automodule:: chem.chemtools
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
.. automodule:: chem.tests
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
*******************************************
|
||||
CMS module
|
||||
*******************************************
|
||||
|
||||
|
||||
.. module:: cms
|
||||
.. toctree::
|
||||
|
||||
transcripts.rst
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
*******************
|
||||
Code Considerations
|
||||
*******************
|
||||
|
||||
This is a checklist of all of the things that we expect a developer to consider
|
||||
as they are building new or modifying existing functionality.
|
||||
|
||||
Operational Impact
|
||||
==================
|
||||
|
||||
* Are there new points in the system that require operational monitoring?
|
||||
|
||||
* External system that you now depend on (Mathworks, SoftwareSecure,
|
||||
CyberSource, etc...)
|
||||
* New reliance on disk space?
|
||||
* New stand process (workers? elastic search?) that need to always be available?
|
||||
* A new queue that needs to be monitored for dequeueing
|
||||
* Bulk Email --> Amazon SES, Inbound queues, etc...
|
||||
* Are important feature metrics sent to datadog and is there a
|
||||
dashboard to monitor them?
|
||||
|
||||
* Am I building a feature that will have impact to the performance of the system?
|
||||
Keep in mind that Open edX needs to support hundreds of thousands if not
|
||||
millions of students, so be careful that you code will work well when the
|
||||
numbers get large.
|
||||
|
||||
* Deep Search
|
||||
* Grade Downloads
|
||||
|
||||
* Are reasonable log messages being written out for debugging purposes?
|
||||
* Will this new feature easily start up in the Vagrant image?
|
||||
* Do we have documentation for how to start up this feature if it has any
|
||||
new startup requirements?
|
||||
* Are there any special directories/file system permissions that need to be set?
|
||||
* Will this have any impact to the CDN related technologies?
|
||||
* Are we pushing any extra manual burden on the Operations team to have to
|
||||
provision anything new when new courses launch? when new schools start? etc....
|
||||
* Has the feature been tested using a production configuration with vagrant?
|
||||
|
||||
See also: :doc:`deploy-new-service`
|
||||
|
||||
Documentation/Training/Support
|
||||
==============================
|
||||
|
||||
* Is there appropriate documentation in the context of the product for
|
||||
this feature? If not, how can we get it to folks?
|
||||
|
||||
* For Studio much of the documentation is in the product.
|
||||
|
||||
* Is this feature big enough that we need to have a session with stakeholders
|
||||
to introduce this feature BEFORE we release it? (PMs, Support, etc...)
|
||||
|
||||
* Paid Certificates
|
||||
|
||||
* Do I have to give some more information to the Escalation Team
|
||||
so that this can be supported?
|
||||
* Did you add an entry to CHANGELOG?
|
||||
* Did you write/edit docstrings for all of your modules, classes, and functions?
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
* Did you consider a reasonable upgrade path?
|
||||
* Is this a feature that we need to slowly roll out to different audiences?
|
||||
|
||||
* Bulk Email
|
||||
|
||||
* Have you considered exposing an appropriate amount of configuration options
|
||||
in case something happens?
|
||||
* Have you considered a simple way to "disable" this feature if something is broken?
|
||||
|
||||
* Centralized Logging
|
||||
|
||||
* Will this feature require any security provisioning?
|
||||
|
||||
* Which roles use this feature? Does it make sense to ensure that only those
|
||||
roles can see this feature?
|
||||
* Assets in the Studio Library
|
||||
|
||||
* Did you ensure that any new libraries are added to appropriate provisioning
|
||||
scripts and have been checked by OSCM for license appropriateness?
|
||||
* Is there an open source alternative?
|
||||
* Are we locked down to any proprietary technologies? (AWS, ...)
|
||||
* Did you consider making APIs so that others can change the implementation if applicable?
|
||||
* Did you consider Internationalization (I18N) and Localization (L10N)?
|
||||
* Did you consider Accessibility (A11y)?
|
||||
* Will your code work properly in workers?
|
||||
* Have you considered the large-scale modularity of the code? For example,
|
||||
xmodule and xblock should not use Django features directly.
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
* Did you make sure that you tried boundary conditions?
|
||||
* Did you try unicode input/data?
|
||||
|
||||
* The name of the person in paid certifactes
|
||||
* The name of the person in bulk email
|
||||
* The body of the text in bulk email
|
||||
* etc
|
||||
|
||||
* Did you try funny characters in the input/data? (~!@#$%^&*()';/.,<>, etc...)
|
||||
* Have you done performance testing on this feature? Do you know how much
|
||||
performance is good enough?
|
||||
* Did you ensure that your functionality works across all supported browsers?
|
||||
* Do you have the right hooks in your HTML to ensure that the views are automatable?
|
||||
* Are you ready if this feature has 10x the expected usage?
|
||||
* What happens if an external service does not respond or responds with
|
||||
a significant delay?
|
||||
* What are possible failure modes? Do your unit tests exercise these code paths?
|
||||
* Does this change affect templates and/or JavaScript? If so, are there
|
||||
Selenium tests for the affected page(s)? Have you tested the affected
|
||||
page(s) in a sandbox?
|
||||
|
||||
Analytics
|
||||
=========
|
||||
|
||||
* Are learning analytics events being recorded in an appropriate way?
|
||||
|
||||
* Do your events use a descriptive and uniquely enough event type and
|
||||
namespace?
|
||||
* Did you ensure that you capture enough information for the researchers
|
||||
to benefit from this event information?
|
||||
* Is it possible to reconstruct the state of your module from the history
|
||||
of its events?
|
||||
* Has this new event been documented so that folks downstream know how
|
||||
to interpret it?
|
||||
* Are you increasing the amount of logging in any major way?
|
||||
|
||||
* Are you sending appropriate/enough information to MixPanel,
|
||||
Google Analytics, Segment IO?
|
||||
|
||||
Collaboration
|
||||
=============
|
||||
* Are there are other teams that would benefit from knowing about this feature?
|
||||
|
||||
* Forums/LMS - email
|
||||
|
||||
* Does this feature require a special broadcast to external teams as well?
|
||||
|
||||
Open Source
|
||||
===========
|
||||
* Can we get help from the community on this feature?
|
||||
* Does the community know enough about this?
|
||||
|
||||
UX/Design/Front End Development
|
||||
===============================
|
||||
* Did you make sure that the feature is going to pass
|
||||
Accessibility requirements (still TBD)?
|
||||
* Did you make sure any system/instructional text is I18N ready?
|
||||
* Did you ensure that basic functionality works across all supported browsers?
|
||||
* Did you plan for the feature's UI to degrade gracefully (or be
|
||||
progressively enhanced) based on browser capability?
|
||||
* Did you review the page/view under all browser/agent conditions -
|
||||
viewport sizes, images off, css off?
|
||||
* Did you write any HTML with ideal page/view semantics in mind?
|
||||
* When writing HTML, did you adhere to standards/conventions around class/id names?
|
||||
* When writing Sass, did you follow OOCSS/SMACSS philosophy ([1]_, [2]_, [3]_),
|
||||
variable/extend organization and naming conventions, and UI abstraction conventions?
|
||||
* When writing Sass, did you document any new variables,
|
||||
extend-based classes, or mixins?
|
||||
* When writing/adding JavaScript, did you consider the asset pipeline
|
||||
and page load timeline?
|
||||
* When writing JavaScript, did you note what code is for prototyping vs. production?
|
||||
* When adding new templates, views, assets (Sass, images, plugins/libraries),
|
||||
did you follow existing naming and file architecture conventions?
|
||||
* When adding new templates, views, assets (Sass, images, plugins/libraries),
|
||||
did you add any needed documentation?
|
||||
* Did you use templates and good Sass architecture to keep DRY?
|
||||
* Did we document any aspects about the feature (flow, purpose, intent)
|
||||
that we or other teams will need to know going forward?
|
||||
|
||||
.. [1] http://smacss.com/
|
||||
.. [2] http://thesassway.com/intermediate/avoid-nested-selectors-for-more-modular-css
|
||||
.. [3] http://ianstormtaylor.com/oocss-plus-sass-is-the-best-way-to-css/
|
||||
|
||||
edX.org Specific
|
||||
================
|
||||
|
||||
* Ensure that you have not broken import/export?
|
||||
* Ensure that you have not broken video player? (Lyla video)
|
||||
@@ -1,16 +0,0 @@
|
||||
Common / lib
|
||||
===============================
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
xmodule.rst
|
||||
modulestore.rst
|
||||
capa.rst
|
||||
chem.rst
|
||||
sandbox-packages.rst
|
||||
symmath.rst
|
||||
calc.rst
|
||||
opaque-keys.rst
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=invalid-name
|
||||
# pylint: disable=redefined-builtin
|
||||
# pylint: disable=protected-access
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
import os
|
||||
from path import path
|
||||
import sys
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
|
||||
sys.path.append('../../../../')
|
||||
|
||||
from docs.shared.conf import *
|
||||
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path.append('source/_templates')
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path.append('source/_static')
|
||||
|
||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
root = path('../../../..').abspath()
|
||||
sys.path.insert(0, root)
|
||||
|
||||
sys.path.append(root / "common/djangoapps")
|
||||
sys.path.append(root / "common/lib")
|
||||
sys.path.append(root / "common/lib/capa")
|
||||
sys.path.append(root / "common/lib/chem")
|
||||
sys.path.append(root / "common/lib/sandbox-packages")
|
||||
sys.path.append(root / "common/lib/xmodule")
|
||||
sys.path.append(root / "common/lib/opaque_keys")
|
||||
sys.path.append(root / "lms/djangoapps")
|
||||
sys.path.append(root / "lms/lib")
|
||||
sys.path.append(root / "cms/djangoapps")
|
||||
sys.path.append(root / "cms/lib")
|
||||
sys.path.insert(
|
||||
0,
|
||||
os.path.abspath(
|
||||
os.path.normpath(
|
||||
os.path.dirname(__file__) + '/../../../'
|
||||
)
|
||||
)
|
||||
)
|
||||
sys.path.append('.')
|
||||
|
||||
# django configuration - careful here
|
||||
if on_rtd:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'lms'
|
||||
else:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'lms.envs.test'
|
||||
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath',
|
||||
'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinxcontrib.napoleon']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['build']
|
||||
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'edXDocs'
|
||||
|
||||
project = u'edX Platform Developer Documentation'
|
||||
copyright = u'2014, edX'
|
||||
|
||||
# --- Mock modules ------------------------------------------------------------
|
||||
|
||||
# Mock all the modules that the readthedocs build can't import
|
||||
|
||||
|
||||
class Mock(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return Mock()
|
||||
|
||||
@classmethod
|
||||
def __getattr__(cls, name):
|
||||
if name in ('__file__', '__path__'):
|
||||
return '/dev/null'
|
||||
elif name[0] == name[0].upper():
|
||||
mockType = type(name, (), {})
|
||||
mockType.__module__ = __name__
|
||||
return mockType
|
||||
else:
|
||||
return Mock()
|
||||
|
||||
# The list of modules and submodules that we know give RTD trouble.
|
||||
# Make sure you've tried including the relevant package in
|
||||
# docs/share/requirements.txt before adding to this list.
|
||||
MOCK_MODULES = [
|
||||
'bson',
|
||||
'bson.errors',
|
||||
'bson.objectid',
|
||||
'dateutil',
|
||||
'dateutil.parser',
|
||||
'fs',
|
||||
'fs.errors',
|
||||
'fs.osfs',
|
||||
'lazy',
|
||||
'mako',
|
||||
'mako.template',
|
||||
'matplotlib',
|
||||
'matplotlib.pyplot',
|
||||
'mock',
|
||||
'numpy',
|
||||
'oauthlib',
|
||||
'oauthlib.oauth1',
|
||||
'oauthlib.oauth1.rfc5849',
|
||||
'PIL',
|
||||
'pymongo',
|
||||
'pyparsing',
|
||||
'pysrt',
|
||||
'requests',
|
||||
'scipy.interpolate',
|
||||
'scipy.constants',
|
||||
'scipy.optimize',
|
||||
'yaml',
|
||||
'webob',
|
||||
'webob.multidict',
|
||||
]
|
||||
|
||||
if on_rtd:
|
||||
for mod_name in MOCK_MODULES:
|
||||
sys.modules[mod_name] = Mock()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# from http://djangosnippets.org/snippets/2533/
|
||||
# autogenerate models definitions
|
||||
|
||||
import inspect
|
||||
import types
|
||||
from HTMLParser import HTMLParser
|
||||
|
||||
|
||||
def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
|
||||
"""
|
||||
Similar to smart_unicode, except that lazy instances are resolved to
|
||||
strings, rather than kept as lazy objects.
|
||||
|
||||
If strings_only is True, don't convert (some) non-string-like objects.
|
||||
"""
|
||||
if strings_only and isinstance(s, (types.NoneType, int)):
|
||||
return s
|
||||
if not isinstance(s, basestring,):
|
||||
if hasattr(s, '__unicode__'):
|
||||
s = unicode(s)
|
||||
else:
|
||||
s = unicode(str(s), encoding, errors)
|
||||
elif not isinstance(s, unicode):
|
||||
s = unicode(s, encoding, errors)
|
||||
return s
|
||||
|
||||
|
||||
class MLStripper(HTMLParser):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
self.fed = []
|
||||
|
||||
def handle_data(self, d):
|
||||
self.fed.append(d)
|
||||
|
||||
def get_data(self):
|
||||
return ''.join(self.fed)
|
||||
|
||||
|
||||
def strip_tags(html):
|
||||
s = MLStripper()
|
||||
s.feed(html)
|
||||
return s.get_data()
|
||||
|
||||
|
||||
def process_docstring(app, what, name, obj, options, lines):
|
||||
"""Autodoc django models"""
|
||||
|
||||
# This causes import errors if left outside the function
|
||||
from django.db import models
|
||||
|
||||
# If you want extract docs from django forms:
|
||||
# from django import forms
|
||||
# from django.forms.models import BaseInlineFormSet
|
||||
|
||||
# Only look at objects that inherit from Django's base MODEL class
|
||||
if inspect.isclass(obj) and issubclass(obj, models.Model):
|
||||
# Grab the field list from the meta class
|
||||
fields = obj._meta._fields()
|
||||
|
||||
for field in fields:
|
||||
# Decode and strip any html out of the field's help text
|
||||
help_text = strip_tags(force_unicode(field.help_text))
|
||||
|
||||
# Decode and capitalize the verbose name, for use if there isn't
|
||||
# any help text
|
||||
verbose_name = force_unicode(field.verbose_name).capitalize()
|
||||
|
||||
if help_text:
|
||||
# Add the model field to the end of the docstring as a param
|
||||
# using the help text as the description
|
||||
lines.append(u':param %s: %s' % (field.attname, help_text))
|
||||
else:
|
||||
# Add the model field to the end of the docstring as a param
|
||||
# using the verbose name as the description
|
||||
lines.append(u':param %s: %s' % (field.attname, verbose_name))
|
||||
|
||||
# Add the field's type to the docstring
|
||||
lines.append(u':type %s: %s' % (field.attname, type(field).__name__))
|
||||
return lines
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""Setup docsting processors"""
|
||||
#Register the docstring processor with sphinx
|
||||
app.connect('autodoc-process-docstring', process_docstring)
|
||||
@@ -1,133 +0,0 @@
|
||||
***********************************
|
||||
So You Want to Deploy a New Service
|
||||
***********************************
|
||||
|
||||
Intro
|
||||
=====
|
||||
|
||||
This page is a work-in-progress aimed at capturing all the details needed to
|
||||
deploy a new service in the edX environment.
|
||||
|
||||
Considerations
|
||||
==============
|
||||
|
||||
What Does Your Service Do
|
||||
-------------------------
|
||||
Understanding how your service works and what it does helps Ops support
|
||||
the service in production.
|
||||
|
||||
Sizing and Resource Profile
|
||||
---------------------------
|
||||
What class of machine does your service require. What resources are most
|
||||
likely to be bottlenecks for your service, CPU, memory, bandwidth, something else?
|
||||
|
||||
Customers
|
||||
---------
|
||||
Who will be consuming your service? What is the anticipated initial usage?
|
||||
What factors will cause usage to grow? How many users can your service support?
|
||||
|
||||
Code
|
||||
----
|
||||
What repository or repositories does your service require.
|
||||
Will your service be deployed from a non-public repo?
|
||||
|
||||
Ideally your service should follow the same release management process as the LMS.
|
||||
This is documented in the wiki, so please ensure you understand that process in depth.
|
||||
|
||||
Was the service code reviewed?
|
||||
|
||||
Settings
|
||||
--------
|
||||
How does your service read in environment specific settings? Were all
|
||||
hard-coded references to values that should be settings, e.g., database URLs
|
||||
and credentials, message queue endpoints, etc., found and resolved during
|
||||
code review?
|
||||
|
||||
License
|
||||
-------
|
||||
Is the license included in the repo?
|
||||
|
||||
How does your service run
|
||||
-------------------------
|
||||
Is it HTTP based? Does it run periodically? Both?
|
||||
|
||||
Persistence
|
||||
-----------
|
||||
Ops will need to know the following things:
|
||||
|
||||
* What persistence needs does you service have
|
||||
|
||||
* Will it connect to an existing database?
|
||||
* Will it connect to Mongo
|
||||
|
||||
* What are the least permissive permissions your service needs to do its job.
|
||||
|
||||
Logging
|
||||
-------
|
||||
|
||||
It's important that your application logging in built out to provide sufficient
|
||||
feedback for problem determination as well as ensuring that it is operating as
|
||||
desired. It's also important that your service log using our deployment
|
||||
standards, i.e., logs vs syslog in deployment environments and utilizes the
|
||||
standard log format for syslog. Can the logs be consumed by Splunk? They
|
||||
should not be if they contain data discussed in the Data Security section below.
|
||||
|
||||
Metrics
|
||||
-------
|
||||
What are the key metrics for your application? Concurrent users?
|
||||
Transactions per second? Ideally you should create a DataDog view that
|
||||
captures the key metrics for your service and provided an instant gauge of
|
||||
overally service health.
|
||||
|
||||
Messaging
|
||||
---------
|
||||
Does your service need to access a message queue.
|
||||
|
||||
Email
|
||||
-----
|
||||
Does your service need to send email
|
||||
|
||||
Access to Other Service
|
||||
-----------------------
|
||||
Does your service need access to other service either within or
|
||||
outside of the edX environment. Some example might be, the comment service,
|
||||
the LMS, YouTube, s3 buckets, etc.
|
||||
|
||||
Service Monitoring
|
||||
------------------
|
||||
Your service should have a facility for remote monitoring that has the
|
||||
following characteristics:
|
||||
|
||||
* It should exercise all the components that your service requires to run successfully.
|
||||
* It should be necessary and sufficient for ensuring your service is healthy.
|
||||
* It should be secure.
|
||||
* It should not open your service to DDOS attacks.
|
||||
|
||||
Fault Tolerance and Scalability
|
||||
-------------------------------
|
||||
How can your application be deployed to ensure that it is fault tolerant
|
||||
and scalable?
|
||||
|
||||
Network Access
|
||||
--------------
|
||||
From where should your service be accessible.
|
||||
|
||||
Data Security
|
||||
-------------
|
||||
Will your application be storing or handling data in any of the
|
||||
following categories:
|
||||
|
||||
* Personally Identifiable Information in General, e.g., user's email addresses.
|
||||
* Tracking log data
|
||||
* edX confidential data
|
||||
|
||||
Testing
|
||||
-------
|
||||
Has your service been load tested? What there the details of the test.
|
||||
What determinations can we make regarding when we will need to scale if usage
|
||||
trend upward? How can ops exercise your service in order to tests end-to-end
|
||||
integration. We love no-op-able tasks.
|
||||
|
||||
Additional Requirements
|
||||
-----------------------
|
||||
Anything else we should know about.
|
||||
@@ -1,54 +0,0 @@
|
||||
*******************************************
|
||||
Common
|
||||
*******************************************
|
||||
|
||||
.. module:: common.djangoapps
|
||||
|
||||
Student
|
||||
=======
|
||||
|
||||
.. automodule:: student
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: student.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: student.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Admin
|
||||
-----
|
||||
|
||||
.. automodule:: student.admin
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
.. automodule:: student.tests
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Management
|
||||
----------
|
||||
|
||||
.. automodule:: student.management
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Migrations
|
||||
----------
|
||||
|
||||
.. automodule:: student.migrations
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,10 +0,0 @@
|
||||
Django applications
|
||||
===============================
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
lms.rst
|
||||
cms.rst
|
||||
djangoapps-common.rst
|
||||
@@ -1,76 +0,0 @@
|
||||
*******************************************
|
||||
Content experiments
|
||||
*******************************************
|
||||
|
||||
This is a brief overview of the support for content experiments in the platform.
|
||||
|
||||
For now, there is only one type of experiment: content split testing. This lets course authors define an experiment with several *experimental conditions*, add xblocks that reference that experiment in various places in the course, and specify what content students in each experimental condition should see. The LMS provides a way to randomly assign students to experimental conditions for each experiment, so that they see the right content at runtime.
|
||||
|
||||
Experimental conditions are essentially just a set of groups to partition users into. This may be useful to other non-experiment uses, so the implementation is done via a generic UserPartition interface. Copying the doc string, a UserPartition is:
|
||||
|
||||
A named way to partition users into groups, primarily intended for running
|
||||
experiments. It is expected that each user will be in at most one group in a
|
||||
partition.
|
||||
|
||||
A Partition has an id, name, description, and a list of groups.
|
||||
The id is intended to be unique within the context where these are used. (e.g. for
|
||||
partitions of users within a course, the ids should be unique per-course)
|
||||
|
||||
There is an XModule helper library ``partitions_service`` that helps manage user partitions from XBlocks (at the moment just from the split_test module). It provides an interface to store and retrieve the groups a user is in for particular partitions.
|
||||
|
||||
User assignments to particular groups within a partition must be persisted. This is done via a User Info service provided by the XBlock runtime, which exposes a generic user tagging interface, allowing storing key-value pairs for the user scoped to a particular course.
|
||||
|
||||
UserPartitions are configured at the course level (makes sense in Studio, for author context, and there's no XBlock scope to store per-course configuration state), and currently exposed via the LMS XBlock runtime as ``runtime.user_partitions``.
|
||||
|
||||
More details on the components below.
|
||||
|
||||
|
||||
User metadata service
|
||||
---------------------
|
||||
|
||||
Goals: provide a standard way to store information about users, to be used e.g. by XBlocks, and make that information easily accessible when looking at analytics.
|
||||
|
||||
When the course context is added to the analytics events, it should add the user's course-specific tags as well.
|
||||
When the users global context is added to analytics events, it should add the user's global tags.
|
||||
|
||||
We have a ``user_api`` app, which has REST interface to "User Preferences" for global preferences, and now a ``user_service.py`` interface that exposes per-course tags, with string keys (<=255 chars) and arbitrary string values. The intention is that the values are fairly short, as they will be included in all analytics events about this user.
|
||||
|
||||
The XBlock runtime includes a ``UserServiceInterface`` mixin that provides access to this interface, automatically filling in the current user and course context. This means that with the current design, an XBlock can't access tags for other users or from other courses.
|
||||
|
||||
To avoid name collisions in the keys, we rely on convention. e.g. the XBlock partition service uses ``'xblock.partition_service.partition_{0}'.format(user_partition.id)``.
|
||||
|
||||
|
||||
|
||||
Where the code is:
|
||||
----------------
|
||||
|
||||
|
||||
common:
|
||||
|
||||
- partitions library--defines UserPartitions, provides partitions_service API.
|
||||
- split_test_module -- a block that has one child per experimental condition (could be a vertical or other container with more blocks inside), and config specifying which child corresponds to which condition.
|
||||
- course_module -- a course has a list of UserPartitions, each of which specifies the set of groups to divide users into.
|
||||
|
||||
LMS:
|
||||
|
||||
- runtime--LmsUserPartitions, UserServiceMixin mixins. Provides a way for the partition_service to get the list of UserPartitions defined in a course, and get/set per-user tags within a course scope.
|
||||
- user_api app -- provides persistence for the user tags.
|
||||
|
||||
Things to watch out for (some not implemented yet):
|
||||
-------------------------------------------
|
||||
|
||||
- grade export needs to be smarter, because different students can see different graded things
|
||||
- grading needs to only grade the children that a particular student sees (so if there are problems in both conditions in a split_test, any student would see only one set)
|
||||
- ui -- icons in sequences need to be passed through
|
||||
- tooltips need to be passed through
|
||||
- author changes post-release: conditions can be added or deleted after an experiment is live. This is usually a bad idea, but can be useful, so it's allowed. Need to handle all the cases.
|
||||
- analytics logging needs to log all the user tags (if we really think it's a good idea). We'll probably want to cache the tags in memory for the duration of the request, being careful that they may change as the request is processed.
|
||||
- need to add a "hiding" interface to XBlocks that verticals, sequentials, and courses understand, to hide children that set it. Then give the split test module a way to say that particular condition should be empty and hidden, and pass that up.
|
||||
- staff view should show all the conditions, clearly marked
|
||||
|
||||
Things to test:
|
||||
- randomization
|
||||
- persistence
|
||||
- correlation between test that use the same groups
|
||||
- non-correlation between tests that use different groups
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
|
||||
.. _Options for Extending the edX Platform:
|
||||
|
||||
##########################################
|
||||
Options for Extending the edX Platform
|
||||
##########################################
|
||||
|
||||
There are several options for extending the Open edX Platform to provide useful
|
||||
and innovative educational content in your courses.
|
||||
|
||||
This section of the developers' documentation lists and explains the different ways to extend the platform, starting with the following table. Click the name of the extension type in the column header for more information.
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* -
|
||||
- :ref:`Custom JavaScript Applications`
|
||||
- LTI
|
||||
- External Graders
|
||||
- XBlocks
|
||||
- Platform Customization
|
||||
* - Development Cost
|
||||
- Low
|
||||
- Low
|
||||
- Medium
|
||||
- Medium
|
||||
- High
|
||||
* - Language
|
||||
- JavaScript
|
||||
- Any
|
||||
- Any
|
||||
- Python
|
||||
- Python
|
||||
* - Development Environment Needed
|
||||
- No
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Self-hosting Needed
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
- No
|
||||
- No
|
||||
* - Need edX Involvement
|
||||
- No
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Clean UI Integration
|
||||
- Yes
|
||||
- No (see LTI)
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Mobile enabled
|
||||
- Possibly
|
||||
- Possibly
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Server Side Grading
|
||||
- Possibly (See JavaScript)
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Usage Data
|
||||
- No (See JavaScript)
|
||||
- No
|
||||
- Limited
|
||||
- Yes
|
||||
- Yes
|
||||
* - Provision in Studio
|
||||
- No
|
||||
- No
|
||||
- No
|
||||
- Yes
|
||||
- No
|
||||
* - Privacy Loss Compared to Hosting Open edX
|
||||
- No
|
||||
- Possibly
|
||||
- Possibly
|
||||
- No
|
||||
- No
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
###########################
|
||||
Extending the edX Platform
|
||||
###########################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
extending.rst
|
||||
javascript
|
||||
js_template_example
|
||||
@@ -1,315 +0,0 @@
|
||||
.. _Custom JavaScript Applications:
|
||||
|
||||
##########################################
|
||||
Custom JavaScript Applications
|
||||
##########################################
|
||||
|
||||
|
||||
*******************************
|
||||
Overview
|
||||
*******************************
|
||||
|
||||
|
||||
You can include custom JavaScript applications (also called custom JavaScript
|
||||
problems or JS Input problems) in a course. You add the application directly
|
||||
into edX Studio.
|
||||
|
||||
When you create a JavaScript application, Studio embeds the problem in an inline
|
||||
frame (HTML ``iframe`` tag) so that students can interact with it in the LMS.
|
||||
|
||||
See the following sections for more information:
|
||||
|
||||
* `Grading Options for Custom JavaScript Applications`_
|
||||
* `Use a JavaScript Application Without Grading`_
|
||||
* `Use a JavaScript Application for a Summative Assessment`_
|
||||
* `Grade the Student Response with Python`_
|
||||
* `XML for Custom JavaScript Applications`_
|
||||
|
||||
See :ref:`The Custom JavaScript Display and Grading Example Template` for
|
||||
information about the template application built in to edX Studio.
|
||||
|
||||
Course staff should see the following sections of the document `Building and Running an edX Course <http://edx.readthedocs.org/projects/ca/en/latest/>`_:
|
||||
|
||||
* `Custom JavaScript Display and Grading <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_
|
||||
|
||||
* `Establishing a Grading Policy <http://edx.readthedocs.org/projects/ca/en/latest/building_course/establish_grading_policy.html>`_
|
||||
|
||||
The rest of this section provides more information for developers who are
|
||||
creating JavaScript applications for courses on the edX platform.
|
||||
|
||||
.. note:: This section assumes proficiency with JavaScript and with how problems
|
||||
are constructed in edX Studio. If you intend to grade students' interactions
|
||||
with your JavaScript application, you must also be proficient with Python.
|
||||
|
||||
|
||||
|
||||
*******************************************************
|
||||
Grading Options for Custom JavaScript Applications
|
||||
*******************************************************
|
||||
|
||||
When using a JavaScript application in your course content, you have three
|
||||
options:
|
||||
|
||||
#. A JavaScript application that visually demonstrates a concept or process. The
|
||||
application would not require student interaction, and students would not be
|
||||
graded.
|
||||
|
||||
#. A JavaScript application that requires student interaction but does not grade
|
||||
performance. Referred to as a formative assessment, such an application
|
||||
provides feedback to students based on their interactions.
|
||||
|
||||
#. A JavaScript application that requires and grades student interaction.
|
||||
Referred to as a summative assessment, such an application can be used to
|
||||
evaluate student learning against a standard. To use the JavaScript
|
||||
application as a summative assessment and have student performance integrated
|
||||
into the edX grading system, you must also use basic Python code in the
|
||||
component.
|
||||
|
||||
These options are explained through examples below.
|
||||
|
||||
*******************************************************
|
||||
Use a JavaScript Application Without Grading
|
||||
*******************************************************
|
||||
|
||||
The simplest option is to use JavaScript to show content to students, and
|
||||
optionally to provide feedback as a formative assessment.
|
||||
|
||||
#. In edX Studio, upload an HTML file that contains the JavaScript you want to
|
||||
show students.
|
||||
#. Copy the **Embed URL** of the file.
|
||||
#. `Create a Custom JavaScript Display and Grading Problem <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_. The template
|
||||
for the problem contains the definition for a sample JavaScript application
|
||||
that requires and grades student interaction.
|
||||
#. Edit the XML of the component to remove grading information and refer to the
|
||||
HTML file you uploaded:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<customresponse>
|
||||
<jsinput
|
||||
width="width needed to display your application"
|
||||
height="height needed to display your application"
|
||||
html_file="Embed URL of the HTML file"
|
||||
sop="false"/>
|
||||
</customresponse>
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<customresponse>
|
||||
<jsinput
|
||||
width="400"
|
||||
height="400"
|
||||
html_file="/static/electrol_demo.html"
|
||||
sop="false"/>
|
||||
</customresponse>
|
||||
|
||||
|
||||
**************************************************************
|
||||
Use a JavaScript Application for a Summative Assessment
|
||||
**************************************************************
|
||||
|
||||
To use a JavaScript Application for a summative assessment and have student
|
||||
results calculated by the edX grading system, you must:
|
||||
|
||||
* Include required functions in the JavaScript application.
|
||||
|
||||
* `getState() Function`_
|
||||
* `setState() Function`_
|
||||
* `getGrade() Function`_
|
||||
|
||||
* Reference functions in the problem XML.
|
||||
|
||||
* `Grade the Student Response with Python`_.
|
||||
|
||||
|
||||
====================
|
||||
getState() Function
|
||||
====================
|
||||
|
||||
Your application must contain a ``getState()`` function that returns the state
|
||||
of all objects as a JSON string.
|
||||
|
||||
The ``getState()`` function retrieves the state of objects in the application,
|
||||
so each student experiences that application in its initial or last saved state.
|
||||
|
||||
The name of the ``getState()`` function must be the value of the ``get_statefn``
|
||||
attribute of the ``jsinput`` element for the problem.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<customresponse cfn="vglcfn">
|
||||
<jsinput get_statefn="JSObject.getState"
|
||||
. . . .
|
||||
|
||||
|
||||
|
||||
====================
|
||||
setState() Function
|
||||
====================
|
||||
|
||||
Your application must contain a ``setState()`` function.
|
||||
|
||||
The ``setState()`` function is executed when the student clicks **Check**.
|
||||
|
||||
The function saves application's state so that the student can later return to
|
||||
the application and find it as he or she left it.
|
||||
|
||||
The name of the ``setState()`` function must be the value of the ``set_statefn``
|
||||
attribute of the ``jsinput`` element for the problem.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<customresponse cfn="vglcfn">
|
||||
<jsinput set_statefn="JSObject.setState"
|
||||
. . . .
|
||||
|
||||
|
||||
====================
|
||||
getGrade() Function
|
||||
====================
|
||||
|
||||
Your application must contain a ``getGrade()`` function.
|
||||
|
||||
The ``getGrade()`` function is executed when the student clicks **Check**. The
|
||||
``getState()`` function must return the state of objects on which grading is
|
||||
based as a JSON string.
|
||||
|
||||
The JSON string returned by ``getGrade()`` is used by the Python code in the
|
||||
problem to determine the student's results, as explained below.
|
||||
|
||||
The name of the ``getGrade()`` function must be the value of the ``gradefn``
|
||||
attribute of the ``jsinput`` element for the problem.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<customresponse cfn="vglcfn">
|
||||
<jsinput gradefn="JSObject.getGrade"
|
||||
. . . .
|
||||
|
||||
***************************************
|
||||
Grade the Student Response with Python
|
||||
***************************************
|
||||
|
||||
To grade a student's interaction with your JavaScript application, you must
|
||||
write Python code in the problem. When a student clicks **Check**, the Python
|
||||
code parses the JSON string returned by the application's ``getGrade()``
|
||||
function and determines if the student's submission is correct or not.
|
||||
|
||||
.. note:: Grading for JavaScript applications supports determining if a student's submission is correct or not. You cannot give partial credit with JavaScript applications.
|
||||
|
||||
In the Python code, you must:
|
||||
|
||||
* Enclose all code in a ``script`` element of type ``loncapa/python``.
|
||||
|
||||
* Import ``json``
|
||||
|
||||
* Define a function that is executed when the student clicks Check. This
|
||||
function:
|
||||
|
||||
* Is placed before the ``customresponse`` element that defines the problem.
|
||||
* By default is named ``vglcfn``
|
||||
* Has two parameters: ``e`` for the submission event, and ``ans``, which is
|
||||
the JSON string returned by the JavaScript function ``getGrade()``.
|
||||
* Must return ``True`` if the student's submission is correct, or ``False`` if
|
||||
it is incorrect.
|
||||
|
||||
The structure of the Python code in the problem is:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<problem>
|
||||
<script type="loncapa/python">
|
||||
import json
|
||||
def vglcfn(e, ans):
|
||||
'''
|
||||
Code that parses ans and returns True or False
|
||||
'''
|
||||
</script>
|
||||
<customresponse cfn="vglcfn">
|
||||
. . . .
|
||||
</problem>
|
||||
|
||||
|
||||
*******************************************************
|
||||
XML for Custom JavaScript Applications
|
||||
*******************************************************
|
||||
|
||||
The problem component XML that you define in Studio to provide students with a
|
||||
JavaScript application has the following structure:
|
||||
|
||||
.. code-block::
|
||||
|
||||
<problem>
|
||||
<!-- Optional script tag for summative assessments -->
|
||||
<script type="loncapa/python">
|
||||
import json
|
||||
def vglcfn(e, ans):
|
||||
'''
|
||||
Code that parses ans and returns True or False
|
||||
'''
|
||||
</script>
|
||||
<customresponse cfn="vglcfn">
|
||||
<jsinput
|
||||
gradefn="JSObject.getGrade"
|
||||
get_statefn="JSObject.getState"
|
||||
set_statefn="JSObject.setState"
|
||||
width="100%"
|
||||
height="360"
|
||||
html_file="/static/file-name.html"
|
||||
sop="false"/>
|
||||
</customresponse>
|
||||
</problem>
|
||||
|
||||
|
||||
===================
|
||||
jsinput attributes
|
||||
===================
|
||||
|
||||
The following table describes the attributes of the ``jsinput`` element.
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 50 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Attribute
|
||||
- Description
|
||||
- Example
|
||||
* - gradefn
|
||||
- The function in your JavaScript application that returns the state of the
|
||||
objects to be evaluated as a JSON string.
|
||||
- ``JSObject.getGrade``
|
||||
* - get_statefun
|
||||
- The function in your JavaScript application that returns the state of the
|
||||
objects.
|
||||
- ``JSObject.getState``
|
||||
* - set_statefun
|
||||
- The function in your JavaScript application that saves the state of the
|
||||
objects.
|
||||
- ``JSObject.setState``
|
||||
* - initial_state
|
||||
- A JSON string representing the initial state, if any, of the objects.
|
||||
- '{"selectedObjects":{"cube":true,"cylinder":false}}'
|
||||
* - width
|
||||
- The width of the IFrame in which your JavaScript application will be
|
||||
displayed, in pixels.
|
||||
- 400
|
||||
* - height
|
||||
- The height of the IFrame in which your JavaScript application will be
|
||||
displayed, in pixels.
|
||||
- 400
|
||||
* - html_file
|
||||
- The name of the HTML file containing your JavaScript application that
|
||||
will be loaded in the IFrame.
|
||||
- /static/webGLDemo.html
|
||||
* - sop
|
||||
- The same-origin policy (SOP), meaning that all elements have the same
|
||||
protocol, host, and port. To bypass the SOP, set to ``true``.
|
||||
- false
|
||||
@@ -1,195 +0,0 @@
|
||||
.. _The Custom JavaScript Display and Grading Example Template:
|
||||
|
||||
###########################################################
|
||||
The Custom JavaScript Display and Grading Example Template
|
||||
###########################################################
|
||||
|
||||
As referred to in `course staff documentation <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_, there is a built-in template in edX Studio that uses a sample JavaScript application.
|
||||
|
||||
This sample application has students select two different shapes, a cone and a
|
||||
cube. The correct state is when the cone is selected and the cube is not
|
||||
selected:
|
||||
|
||||
.. image:: ../images/JavaScriptInputExample.png
|
||||
:alt: Image of the sample JavaScript application, with the cone selected
|
||||
|
||||
You can `download files for that application <http://files.edx.org/JSInput.zip>`_.
|
||||
You must upload these files in Studio to use them in a problem.
|
||||
|
||||
The following information steps through this example to demonstrate how to apply
|
||||
the guidelines in `Custom JavaScript Display and Grading`.
|
||||
|
||||
|
||||
****************************
|
||||
Example getState() Function
|
||||
****************************
|
||||
|
||||
In the example, the ``state`` variable is initialized for the cylinder and cube
|
||||
in the ``WebGLDemo.js`` file:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
var state = {
|
||||
'selectedObjects': {
|
||||
'cylinder': false,
|
||||
'cube': false
|
||||
}
|
||||
}
|
||||
|
||||
User interactions toggle the ``state`` values of the cylinder and cube between
|
||||
``true`` and ``false``.
|
||||
|
||||
The ``getState()`` function in the sample application returns the state as a
|
||||
JSON string:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function getState() {
|
||||
return JSON.stringify(state);
|
||||
}
|
||||
|
||||
|
||||
******************************
|
||||
Example setState() Function
|
||||
******************************
|
||||
|
||||
In the example, when a student clicks **Check**, the ``state`` variable is saved
|
||||
so that the student can later return to the application and find it in the same
|
||||
state:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function setState() {
|
||||
stateStr = arguments.length === 1 ? arguments[0] : arguments[1];
|
||||
state = JSON.parse(stateStr);
|
||||
updateMaterials();
|
||||
}
|
||||
|
||||
The ``updateMaterials()`` function called by ``setState()`` updates the state of
|
||||
the cylinder and cone with the user's current selections:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function updateMaterials() {
|
||||
if (state.selectedObjects.cylinder) {
|
||||
cylinder.material = selectedMaterial;
|
||||
}
|
||||
else {
|
||||
cylinder.material = unselectedMaterial;
|
||||
}
|
||||
|
||||
if (state.selectedObjects.cube) {
|
||||
cube.material = selectedMaterial;
|
||||
}
|
||||
else {
|
||||
cube.material = unselectedMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
******************************
|
||||
Example getGrade() function
|
||||
******************************
|
||||
|
||||
In the example, when a student clicks **Check**, the ``getGrade()`` function in
|
||||
returns the selected objects:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function getGrade() {
|
||||
return JSON.stringify(state['selectedObjects']);
|
||||
}
|
||||
|
||||
The returned JSON string is then used by the Python code defined in the problem
|
||||
to determine if correct objects were selected or not, and to return a result.
|
||||
|
||||
*******************************
|
||||
Grade the Student Response
|
||||
*******************************
|
||||
|
||||
|
||||
The following is the Python function ``vglcfn`` in the sample application:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
<script type="loncapa/python">
|
||||
import json
|
||||
def vglcfn(e, ans):
|
||||
'''
|
||||
par is a dictionary containing two keys, "answer" and "state"
|
||||
The value of answer is the JSON string returned by getGrade
|
||||
The value of state is the JSON string returned by getState
|
||||
'''
|
||||
par = json.loads(ans)
|
||||
# We can use either the value of the answer key to grade
|
||||
answer = json.loads(par["answer"])
|
||||
return answer["cylinder"] and not answer["cube"]
|
||||
'''
|
||||
# Or we could use the value of the state key
|
||||
state = json.loads(par["state"])
|
||||
selectedObjects = state["selectedObjects"]
|
||||
return selectedObjects["cylinder"] and not selectedObjects["cube"]
|
||||
'''
|
||||
</script>
|
||||
|
||||
The ``ans`` parameter contains the JSON string returned by ``getGrade()``. The
|
||||
value is converted to a Python Unicode structure in the variable ``par``.
|
||||
|
||||
In the function's first option, object(s) the student selected are stored in the
|
||||
``answer`` variable. If the student selected the cylinder and not the cube, the
|
||||
``answer`` variable contains only ``cylinder``, and the function returns
|
||||
``True``, which signifies a correct answer. Otherwise, it returns ``False`` and
|
||||
the answer is incorrect.
|
||||
|
||||
In the function's second option, the objects' states are retrieved. If the
|
||||
cylinder is selected and not the cube, the function returns ``True``, which
|
||||
signifies a correct answer. Otherwise, it returns ``False`` and the answer is
|
||||
incorrect.
|
||||
|
||||
|
||||
*******************************
|
||||
XML Problem Structure
|
||||
*******************************
|
||||
|
||||
The XML problem for the sample template is:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<problem display_name="webGLDemo">
|
||||
<script type="loncapa/python">
|
||||
import json
|
||||
def vglcfn(e, ans):
|
||||
'''
|
||||
par is a dictionary containing two keys, "answer" and "state"
|
||||
The value of answer is the JSON string returned by getGrade
|
||||
The value of state is the JSON string returned by getState
|
||||
'''
|
||||
par = json.loads(ans)
|
||||
# We can use either the value of the answer key to grade
|
||||
answer = json.loads(par["answer"])
|
||||
return answer["cylinder"] and not answer["cube"]
|
||||
'''
|
||||
# Or we could use the value of the state key
|
||||
state = json.loads(par["state"])
|
||||
selectedObjects = state["selectedObjects"]
|
||||
return selectedObjects["cylinder"] and not selectedObjects["cube"]
|
||||
'''
|
||||
</script>
|
||||
<p>
|
||||
The shapes below can be selected (yellow) or unselected (cyan).
|
||||
Clicking on them repeatedly will cycle through these two states.
|
||||
</p>
|
||||
<p>
|
||||
If the cone is selected (and not the cube), a correct answer will be
|
||||
generated after pressing "Check". Clicking on either "Check" or "Save"
|
||||
will register the current state.
|
||||
</p>
|
||||
<customresponse cfn="vglcfn">
|
||||
<jsinput gradefn="WebGLDemo.getGrade"
|
||||
get_statefn="WebGLDemo.getState"
|
||||
set_statefn="WebGLDemo.setState"
|
||||
width="400"
|
||||
height="400"
|
||||
html_file="https://studio.edx.org/c4x/edX/DemoX/asset/webGLDemo.html"
|
||||
sop="false"/>
|
||||
</customresponse>
|
||||
</problem>
|
||||
@@ -1,589 +0,0 @@
|
||||
######################################
|
||||
Internationalization coding guidelines
|
||||
######################################
|
||||
|
||||
Preparing code to be presented in many languages can be complex and difficult.
|
||||
The rules here give the best practices for marking English strings in source
|
||||
so that it can be extracted, translated, and presented to the user in the
|
||||
language of their choice.
|
||||
|
||||
See also:
|
||||
|
||||
* `Django Internationalization <https://docs.djangoproject.com/en/dev/topics/i18n/>`_ (overview)
|
||||
* `Django: Internationalizing Python code <https://docs.djangoproject.com/en/dev/topics/i18n/translation/#internationalization-in-python-code>`_
|
||||
* `Django Translation guidelines <https://docs.djangoproject.com/en/dev/topics/i18n/translation/>`_
|
||||
* `Django Format localization <https://docs.djangoproject.com/en/dev/topics/i18n/formatting/>`_
|
||||
|
||||
Presented in this document are the following sections:
|
||||
|
||||
* `General internationalization rules`_
|
||||
* `Editing source files`_
|
||||
* `Coverage testing`_
|
||||
* `Style guidelines`_
|
||||
|
||||
|
||||
General internationalization rules
|
||||
**********************************
|
||||
|
||||
In order to localize source files, we need to prepare them so that the
|
||||
human-readable strings can be extracted by a pre-processing step, and then have
|
||||
localized strings used at runtime. This requires attention to detail, and
|
||||
unfortunately limits what you can do with strings in the code. In general:
|
||||
|
||||
1. Always mark complete sentences for translation. If you combine fragments at
|
||||
runtime, there is no way for the translator to construct a proper sentence
|
||||
in their language.
|
||||
|
||||
2. Don't join strings together at runtime to create sentences.
|
||||
|
||||
3. Limit the amount of text in strings that is not presented to the user. HTML
|
||||
markup is better applied after the translation. If you give HTML to the
|
||||
translators, there's a good chance they will translate your tags or
|
||||
attributes.
|
||||
|
||||
4. Use placeholders with descriptive names: ``"Welcome {student_name}"`` is
|
||||
much better than ``"Welcome {0}"``.
|
||||
|
||||
See the detailed Style Guidelines at the end for details.
|
||||
|
||||
|
||||
Editing source files
|
||||
********************
|
||||
|
||||
While editing source files (including Python, JavaScript, or HTML template
|
||||
files), use the appropriate conventions. There are a few things to know how to
|
||||
do:
|
||||
|
||||
1. What has to be at the top of the file (if anything) to prepare it for i18n.
|
||||
|
||||
2. How are strings marked for internationalization? This takes the form of a
|
||||
function call with the string as an argument.
|
||||
|
||||
3. How are translator comments indicated? These are comments in the file that
|
||||
will travel with the strings to the translators, giving them context to
|
||||
produce the best translation. They have a "Translators:" marker. They must
|
||||
appear on the line preceding the text they describe. Multi-line comments
|
||||
are supported for Python in case the translator comment needs to be wrapped.
|
||||
|
||||
The code samples below show how to do each of these things for:
|
||||
|
||||
* `Python source code`_
|
||||
* `Django template files`_
|
||||
* `Mako template files`_
|
||||
* `JavaScript files`_
|
||||
* `Coffeescript files`_
|
||||
* `Underscore template files`_
|
||||
* `Other kinds of code`_
|
||||
|
||||
Note that you have to take into account not just the programming language involved,
|
||||
but the type of file: JavaScript embedded in an HTML Mako template is treated differently
|
||||
than JavaScript in a pure .js file.
|
||||
|
||||
Python source code
|
||||
==================
|
||||
|
||||
.. highlight:: python
|
||||
|
||||
In most Python source code (read the Django docs for more details)::
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
# Translators: This will help the translator
|
||||
message = _("Welcome!")
|
||||
|
||||
# Translators: This is a very long comment that needs to wrap
|
||||
# over multiple lines because it would be too long otherwise.
|
||||
message = _("Hello world")
|
||||
|
||||
Some edX code cannot use Django imports. To maintain portability, XBlocks,
|
||||
XModules, Inputtypes and Responsetypes forbid importing Django. Each of these
|
||||
has its own way of accessing translations. You'll use lines like these
|
||||
instead::
|
||||
|
||||
### for XBlock & XModule:
|
||||
_ = self.runtime.service(self, "i18n").ugettext
|
||||
# Translators: a greeting to newly-registered students.
|
||||
message = _("Welcome!")
|
||||
|
||||
# for InputType and ResponseType:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
# Translators: a greeting to newly-registered students.
|
||||
message = _("Welcome!")
|
||||
|
||||
"Translators" comments will work in these places too, so don't be shy about
|
||||
providing clarifying comments to the translators.
|
||||
|
||||
|
||||
Django template files
|
||||
=====================
|
||||
|
||||
.. highlight:: django
|
||||
|
||||
In Django template files (`templates/*.html`)::
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{# Translators: this will help the translator. #}
|
||||
{% trans "Welcome!" %}
|
||||
|
||||
Mako template files
|
||||
===================
|
||||
|
||||
.. highlight:: mako
|
||||
|
||||
In Mako template files (`templates/*.html`), you can use all of the tools
|
||||
available to python programmers. Just make sure to import the relevant
|
||||
functions first. Here's a Mako template example::
|
||||
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
## Translators: message to the translator
|
||||
${_("Welcome!")}
|
||||
|
||||
JavaScript files
|
||||
================
|
||||
|
||||
.. highlight:: javascript
|
||||
|
||||
In order to internationalize JavaScript, first the HTML template (base.html)
|
||||
must load a special JavaScript library (and Django must be configured to serve
|
||||
it)::
|
||||
|
||||
<script type="text/javascript" src="jsi18n/"></script>
|
||||
|
||||
Then, in JavaScript files (`*.js`)::
|
||||
|
||||
// Translators: this will help the translator.
|
||||
var message = gettext('Welcome!');
|
||||
|
||||
Note that JavaScript embedded in HTML in a Mako template file is handled
|
||||
differently. There, you use the Mako syntax even within the JavaScript.
|
||||
|
||||
Coffeescript files
|
||||
==================
|
||||
|
||||
.. highlight:: coffeescript
|
||||
|
||||
Coffeescript files are compiled to JavaScript files, so it works mostly like
|
||||
JavaScript::
|
||||
|
||||
`// Translators: this will help the translator.`
|
||||
message = gettext('Hey there!')
|
||||
# Interpolation has to be done in JavaScript, not Coffeescript:
|
||||
message = gettext("Error getting student progress url for '<%= student_id %>'.")
|
||||
full_message = _.template(message, {student_id: unique_student_identifier})
|
||||
|
||||
But because we extract strings from the compiled .js files, there are some
|
||||
native Coffeescript features that break the extraction from the .js files:
|
||||
|
||||
1. You cannot use Coffeescript string interpolation: This results in string
|
||||
concatenation in the .js file, so string extraction won't work.
|
||||
|
||||
2. You cannot use Coffeescript comments for translator comments, since they are
|
||||
not passed through to the JavaScript file.
|
||||
|
||||
::
|
||||
|
||||
# NO NO not like this:
|
||||
# Translators: this won't get to the translators!
|
||||
message = gettext("Welcome, #{student_name}!") # This won't work!
|
||||
|
||||
# YES like this:
|
||||
`// Translators: this will get to the translators.`
|
||||
message = gettext("This works")
|
||||
|
||||
###
|
||||
Translators: This will work, but takes three lines :(
|
||||
###
|
||||
message = gettext("Hey there")
|
||||
|
||||
.. highlight:: python
|
||||
|
||||
Underscore template files
|
||||
=========================
|
||||
|
||||
Underscore template files are used in conjunction with JavaScript, and so the
|
||||
same techniques are used for localization. Ensure that the i18n JavaScript
|
||||
library has already been loaded, and then use the regular i18n functions
|
||||
such as ``gettext`` and ``interpolate`` from your template.
|
||||
|
||||
For example::
|
||||
|
||||
<%-
|
||||
interpolate(
|
||||
gettext('This post is visible only to %(group_name)s.'),
|
||||
{group_name: group.group_name},
|
||||
true
|
||||
)
|
||||
%>
|
||||
|
||||
Note: it is recommended that you use ``<%-`` for all translated strings
|
||||
as this will HTML escape the string before including it in the page. This
|
||||
ensures that translations are free to use non-HTML characters.
|
||||
|
||||
Other kinds of code
|
||||
===================
|
||||
|
||||
We have not yet established guidelines for internationalizing the following.
|
||||
|
||||
* Course content (such as subtitles for videos)
|
||||
|
||||
* Documentation (written for Sphinx as .rst files)
|
||||
|
||||
|
||||
Building and testing your code
|
||||
******************************
|
||||
|
||||
These instructions assume you are a developer writing new code to check in to
|
||||
Github. For other use cases in the translation life cycle (such as translating
|
||||
the strings, or checking the translations into Github, see use cases).
|
||||
|
||||
1. Create human-readable .po files with the latest strings. This command may
|
||||
take a minute or two to complete::
|
||||
|
||||
$ cd edx-platform
|
||||
$ paver i18n_extract
|
||||
|
||||
2. Generate dummy strings: See coverage testing (below) for more details. This
|
||||
will create an "Esperanto" translation that is actually over-accented
|
||||
English. Use this to create fake translations::
|
||||
|
||||
$ paver i18n_dummy
|
||||
|
||||
3. Run the paver i18n_generate command to create machine-readable .mo files::
|
||||
|
||||
$ paver i18n_generate
|
||||
|
||||
4. Django should be ready to go. The next time you run Studio or LMS, append
|
||||
``?preview-lang=eo`` to the URL to turn on Esperanto as a dark language. The
|
||||
accented-English strings (from step 3, above) should be displayed.
|
||||
|
||||
If you experience issues, be sure that your settings for ``USE_I18N`` and
|
||||
``USE_L10N`` are both set to True.
|
||||
|
||||
5. With Esperanto turned on as a dark language (see Step 4), review the pages
|
||||
affected by your code and verify that you see fake translations. If you see
|
||||
plain English instead, your code is not being properly translated. Review
|
||||
the steps in editing source files (above).
|
||||
|
||||
6. When you are done reviewing, append ``?clear-lang`` to the LMS or Studio URL
|
||||
to reset your session to English.
|
||||
|
||||
|
||||
Coverage testing
|
||||
****************
|
||||
|
||||
This tool is used during the bootstrap phase, when presumably (1) there is a
|
||||
lot of edX source code to be converted, and (2) there are not a lot of
|
||||
available translations for externalized edX strings. At the end of the
|
||||
bootstrap phase, we will eventually deprecate this tool in favor of other
|
||||
processes. Once most of the edX source code has been successfully converted,
|
||||
and there are several full translations available, it will be easier to detect
|
||||
and correct specific gaps in compliance.
|
||||
|
||||
Use the coverage tool to generate dummy files::
|
||||
|
||||
$ paver i18n_dummy
|
||||
|
||||
This will create new dummy translations in the Esperanto directory
|
||||
(edx-platform/conf/local/eo/LC_MESSAGES).
|
||||
|
||||
You can then configure your browser preferences to view Esperanto as your
|
||||
preferred language. Instead of plain English strings, you should see something
|
||||
like this:
|
||||
|
||||
Thé Fütüré øf Ønlïné Édüçätïøn Ⱡσяєм ι#
|
||||
Før änýøné, änýwhéré, änýtïmé Ⱡσяєм #
|
||||
|
||||
This dummy text is distinguished by extra accent characters. If you see plain
|
||||
English instead (without these accents), it most likely means the string has
|
||||
not been externalized yet. To fix this:
|
||||
|
||||
* Find the string in the source tree (either in Python, JavaScript, or HTML
|
||||
template code).
|
||||
|
||||
* Refer to the above coding guidelines to make sure it has been externalized
|
||||
properly.
|
||||
|
||||
* Rerun the scripts and confirm that the strings are now properly converted
|
||||
into dummy text.
|
||||
|
||||
This dummy text is also distinguished by Lorem ipsum text at the end of each
|
||||
string, and is always terminated with "#". The original English string is
|
||||
padded by about 30% extra characters, to simulate some language (like German)
|
||||
which tend to have longer strings than English. If you see problems with your
|
||||
page layout, such as columns that don't fit, or text that is truncated (the
|
||||
``#`` character should always be displayed on every string), then you will
|
||||
probably need to fix the page layouts accordingly to accommodate the longer
|
||||
strings.
|
||||
|
||||
|
||||
Style guidelines
|
||||
****************
|
||||
|
||||
Don't append strings, interpolate values
|
||||
========================================
|
||||
|
||||
It is harder for translators to provide reasonable translations of small
|
||||
sentence fragments. If your code appends sentence fragments, even if it seems
|
||||
to work OK for English, the same concatenation is very unlikely to work
|
||||
properly for other languages.
|
||||
|
||||
Bad::
|
||||
|
||||
message = _("The directory has ") + len(directory.files) + _(" files.")
|
||||
|
||||
In this scenario, the translator will have to figure out how to translate these
|
||||
two separate strings. It is very difficult to translate a fragment like "The
|
||||
directory has." In some languages the fragments will be in different order. For
|
||||
example, in Japanese, "files" will come before "has."
|
||||
|
||||
It is much easier for a translator to figure out how to translate the entire
|
||||
sentence, using the pattern "The directory has {file_count} files."
|
||||
|
||||
Good::
|
||||
|
||||
message = _("The directory has {file_count} files.").format(file_count=directory.files)
|
||||
|
||||
|
||||
Use named placeholders
|
||||
======================
|
||||
|
||||
Python string formatting provides both positional and named placeholders. Use
|
||||
named placeholders, never use positional placeholders. Positional placeholders
|
||||
can't be translated into other languages which may need to re-order them to
|
||||
make syntactically correct sentences. Even with a single placeholder, a named
|
||||
placeholder provides more context to the translator.
|
||||
|
||||
Bad::
|
||||
|
||||
message = _('Today is %s %d.') % (m, d)
|
||||
|
||||
OK::
|
||||
|
||||
message = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
|
||||
|
||||
Best::
|
||||
|
||||
message = _('Today is {month} {day}.').format(month=m, day=d)
|
||||
|
||||
Notice that in English, the month comes first, but in Spanish the day comes
|
||||
first. This is reflected in the .po file like this::
|
||||
|
||||
# fragment from edx-platform/conf/locale/es/LC_MESSAGES/django.po
|
||||
msgid "Today is {month} {day}."
|
||||
msgstr "Hoy es {day} de {month}."
|
||||
|
||||
The resulting output is correct in each language::
|
||||
|
||||
English output: "Today is November 26."
|
||||
Spanish output: "Hoy es 26 de Noviembre."
|
||||
|
||||
|
||||
Only translate literal strings
|
||||
==============================
|
||||
|
||||
As programmers, we're used to using functions in flexible ways. But the
|
||||
translation functions like ``_()`` and ``gettext()`` can't be used like other
|
||||
functions. At runtime, they are real functions like any other, but they also
|
||||
serve as markers for the string extraction process.
|
||||
|
||||
For string extraction to work properly, the translation functions must be
|
||||
called with only literal strings. If you use them with a computed value,
|
||||
the string extracter won't have a string to extract.
|
||||
|
||||
The difference between the right way and the wrong way can be very subtle:
|
||||
|
||||
::
|
||||
|
||||
# BAD: This tries to translate the result of .format()
|
||||
_("Welcome, {name}".format(name=student_name))
|
||||
|
||||
# GOOD: Translate the literal string, then use it with .format()
|
||||
_("Welcome, {name}").format(name=student_name))
|
||||
|
||||
::
|
||||
|
||||
# BAD: The dedent always makes the same string, but the extractor can't find it.
|
||||
_(dedent("""
|
||||
.. very long message ..
|
||||
"""))
|
||||
|
||||
# GOOD: Dedent the translated string.
|
||||
dedent(_("""
|
||||
.. very long message ..
|
||||
"""))
|
||||
|
||||
::
|
||||
|
||||
# BAD: The string is separated from _(), the extractor won't find it.
|
||||
if hello:
|
||||
msg = "Welcome!"
|
||||
else:
|
||||
msg = "Goodbye."
|
||||
message = _(msg)
|
||||
|
||||
# GOOD: Each string is wrapped in _()
|
||||
if hello:
|
||||
message = _("Welcome!")
|
||||
else:
|
||||
message = _("Goodbye.")
|
||||
|
||||
|
||||
Be aware of nested syntax
|
||||
=========================
|
||||
|
||||
When translating strings in templated files, you have to be careful of nested
|
||||
syntax. For example, consider this JavaScript fragment in a Mako template::
|
||||
|
||||
<script>
|
||||
var feeling = '${_("I love you.")';
|
||||
</script>
|
||||
|
||||
When rendered for a French speaker, it will produce this::
|
||||
|
||||
<script>
|
||||
var feeling = 'Je t'aime.';
|
||||
</script>
|
||||
|
||||
which is now invalid JavaScript. This can be avoided by using double-quotes
|
||||
for the JavaScript string. The better solution is to use a filtering function
|
||||
that properly escapes the string for JavaScript use::
|
||||
|
||||
<%!
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.html import escapejs
|
||||
%>
|
||||
...
|
||||
<script>
|
||||
var feeling = '${escapejs(_("I love you."))}';
|
||||
</script>
|
||||
|
||||
which produces::
|
||||
|
||||
<script>
|
||||
var feeling = 'Je t\'aime.';
|
||||
</script>
|
||||
|
||||
Other places that might be problematic are HTML attributes::
|
||||
|
||||
<img alt='${_("I love you.")}'>
|
||||
|
||||
|
||||
Singular vs plural
|
||||
==================
|
||||
|
||||
It's tempting to improve a message by selecting singular or plural based on a
|
||||
count::
|
||||
|
||||
if count == 1:
|
||||
msg = _("There is 1 file.")
|
||||
else:
|
||||
msg = _("There are {file_count} files.").format(file_count=count)
|
||||
|
||||
This is not the correct way to choose a string, because other languages have
|
||||
different rules for when to use singular and when plural, and there may be more
|
||||
than two choices!
|
||||
|
||||
One option is not to use different text for different counts::
|
||||
|
||||
msg = _("Number of files: {file_count}").format(file_count=count)
|
||||
|
||||
If you want to choose based on number, you need to use another gettext variant
|
||||
to do it::
|
||||
|
||||
from django.utils.translation import ungettext
|
||||
msg = ungettext("There is {file_count} file", "There are {file_count} files", count)
|
||||
msg = msg.format(file_count=count)
|
||||
|
||||
This will properly use count to find a correct string in the translation file,
|
||||
and then you can use that string to format in the count.
|
||||
|
||||
|
||||
Translating too early
|
||||
=====================
|
||||
|
||||
When the ``_()`` function is called, it will fetch a translated string. It
|
||||
will use the current user's language to decide which string to fetch. If you
|
||||
invoke it before we know the user, then it will get the wrong language.
|
||||
|
||||
For example::
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
HELLO = _("Hello")
|
||||
GOODBYE = _("Goodbye")
|
||||
|
||||
def get_greeting(hello):
|
||||
if hello:
|
||||
return HELLO
|
||||
else:
|
||||
return GOODBYE
|
||||
|
||||
Here the HELLO and GOODBYE constants are assigned when the module is first
|
||||
imported, at server startup. There is no current user then, so ugettext will
|
||||
use the server's default language. When we eventually use those constants to
|
||||
show a message to the user, they won't be looked up again, and the user will
|
||||
get the wrong language.
|
||||
|
||||
There are a few ways to deal with this. The first is to avoid calling ``_()``
|
||||
until we have the user::
|
||||
|
||||
def get_greeting(hello):
|
||||
if hello:
|
||||
return _("Hello")
|
||||
else:
|
||||
return _("Goodbye")
|
||||
|
||||
Another way is to use Django's ugettext_lazy function. Instead of returning
|
||||
a string, it returns a lazy object that will wait to do the lookup until it is
|
||||
actually used as a string:
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
This can be tricky because the lazy object doesn't act like a string in all
|
||||
cases.
|
||||
|
||||
The last way to solve the problem is to mark the string so that it will be
|
||||
extracted properly, but not actually do the lookup when the constant is
|
||||
defined::
|
||||
|
||||
from django.utils.translation import ugettext
|
||||
|
||||
_ = lambda text: text
|
||||
|
||||
HELLO = _("Hello")
|
||||
GOODBYE = _("Goodbye")
|
||||
|
||||
def get_greeting(hello):
|
||||
if hello:
|
||||
return ugettext(HELLO)
|
||||
else:
|
||||
return ugettext(GOODBYE)
|
||||
|
||||
Here we define ``_()`` as a pass-through function, so the string will be found
|
||||
during extraction, but won't be translated too early. Then we use the real
|
||||
translation function at runtime to get the localized string.
|
||||
|
||||
Multiline Strings
|
||||
=================
|
||||
|
||||
Translator notes must directly precede the string literals to which they refer.
|
||||
For example, the translator note here will not be passed along to translators::
|
||||
|
||||
# Translators: you will not be able to see this note because
|
||||
# I do not directly prepend the line with the translated string literal.
|
||||
# See the line directly below this one does not contain part of the string?
|
||||
long_translated_string = _(
|
||||
"I am a long string, with many, many words. So many words that it is "
|
||||
"advisable that I be split over this line."
|
||||
)
|
||||
|
||||
In such a case, make sure you format your code so that the string begins on
|
||||
a line directly below the translator note::
|
||||
|
||||
# Translators: you will be able to see this note.
|
||||
# See how the line directly below this one contains the start of the string?
|
||||
long_translated_string = _("I am a long string, with many, many words. "
|
||||
"So many words that it is advisable that I "
|
||||
"be split over this line.")
|
||||
@@ -1,361 +0,0 @@
|
||||
##############################
|
||||
Guidelines for Translating edX
|
||||
##############################
|
||||
|
||||
Open edX uses **Transifex**, an open source translation platform, to power
|
||||
the translation of edX software into different languages. All translations
|
||||
are hosted at `Transifex.com <https://www.transifex.com/>`_, which provides
|
||||
a web application allowing translators to write, submit, and manage their
|
||||
translations.
|
||||
|
||||
This page explains how to get started with Transifex and provides guidelines
|
||||
for translators to follow when executing translations. For further discussion,
|
||||
we welcome you to join the `openedx-translation <https://groups.google.com/forum/#!forum/openedx-translation>`_
|
||||
mailing list.
|
||||
|
||||
For information on the Transifex process, see the following sections:
|
||||
|
||||
* `Getting Started with Transifex`_
|
||||
* `Guidelines for Translators`_
|
||||
|
||||
See also documentation on
|
||||
`public translation sandboxes <public_sandboxes.rst#language-sandboxes>`_.
|
||||
|
||||
Getting Started with Transifex
|
||||
******************************
|
||||
|
||||
Contributors wishing to help translate edx-platform and
|
||||
associated projects can find edX translation projects on
|
||||
`Transifex <https://www.transifex.com/organization/open-edx/dashboard>`_.
|
||||
Note: All strings must be both translated **and reviewed** before
|
||||
we will publish them on the edx.org website.
|
||||
|
||||
You should become a translator only if you feel very confident
|
||||
in both your language in English. Open edX is written in English, so all
|
||||
translations will be done from English to your language.
|
||||
|
||||
This guide shows images from the Transifex website in English. Depending
|
||||
on your browser settings, you may see the site in a different language. The
|
||||
button locations will be the same.
|
||||
|
||||
This section contains the following subsections:
|
||||
|
||||
* `Signing Up For An Account`_
|
||||
* `Joining A Translation Team`_
|
||||
* `Joining A Review Team`_
|
||||
* `How To Translate With Transifex`_
|
||||
* `Requesting A New Language`_
|
||||
|
||||
Signing Up For An Account
|
||||
=========================
|
||||
Go to `https://www.transifex.com/signup/ <https://www.transifex.com/signup/>`_
|
||||
and fill out the form to create your free Transifex account, if you don't already
|
||||
have one.
|
||||
|
||||
Joining A Translation Team
|
||||
==========================
|
||||
|
||||
1. Once you've set up your account, visit the `edx-platform project <https://www.transifex.com/projects/p/edx-platform/>`_
|
||||
to become a translator for your language.
|
||||
|
||||
2. When you visit the project page, it looks like this. If your language is listed, click
|
||||
on the name of the language to go to the language's page. Here is an example of choosing
|
||||
the Japanese translation project:
|
||||
|
||||
.. image:: images/edx-platform-transifex-project.png
|
||||
|
||||
3. Once you're on the language's page, click "Join team" to become part of the translation team
|
||||
for that language:
|
||||
|
||||
.. image:: images/join-language-team.png
|
||||
|
||||
Once you've joined a translation team, you can begin translating strings immediately! See the
|
||||
section `Using Transifex`_.
|
||||
|
||||
Joining A Review Team
|
||||
=====================
|
||||
|
||||
Optionally, you can request to become a `reviewer <http://support.transifex.com/customer/portal/articles/1167280>`_
|
||||
for a language. Review teams are incredibly important, because
|
||||
all strings must be both translated **and reviewed** before
|
||||
we will publish them on the edx.org website.
|
||||
|
||||
You should join a review team only if you feel very confident in both your language
|
||||
and in English. To join a review team, request permission from the project coordinator(s).
|
||||
|
||||
1. Click on the "Members" tab of your language:
|
||||
|
||||
.. image:: images/view-team-members.png
|
||||
|
||||
You'll see a list of all the members of your translation team.
|
||||
|
||||
2. Click on one of the Coordinators for the language to be brought to their profile page,
|
||||
where you can click the "Send message" button to email them and ask for Reviewer access:
|
||||
|
||||
.. image:: images/send-message-button.png
|
||||
|
||||
If the coordinator don't respond, try messaging another coordinator, or message one of the edX project maintainers.
|
||||
You can find the project maintainers at the top of the main project page:
|
||||
|
||||
.. image:: images/project-maintainers.png
|
||||
|
||||
If you are willing to become a coordinator for your language, let us know in your message.
|
||||
|
||||
How To Translate With Transifex
|
||||
===============================
|
||||
|
||||
Once you are a member of a translation or review team, you can click on any of the resources in
|
||||
the project to begin translating it. For help documentation on Transifex, see the `Transifex translators
|
||||
help desk <http://support.transifex.com/customer/portal/topics/414107-translators/articles>`_.
|
||||
Before you begin, be sure you've reviewed the `Guidelines for Translators`_.
|
||||
|
||||
When visiting a language page, you will see a list of ten distinct resources to translate:
|
||||
|
||||
.. image:: images/project-resources.png
|
||||
|
||||
Focus on translating the non-Studio resources first. That is, please first
|
||||
translate and review these resources, in this order, before anything else:
|
||||
|
||||
* messages
|
||||
* mako
|
||||
* django-partial
|
||||
* djangojs-partial
|
||||
* wiki
|
||||
* notifier-django
|
||||
* comments-service
|
||||
|
||||
*Only after* the above resources are 100% translated and reviewed, move on to the Studio resources:
|
||||
|
||||
* mako-studio
|
||||
* djangojs-studio
|
||||
* django-studio
|
||||
|
||||
Requesting A New Language
|
||||
=========================
|
||||
|
||||
If your language is **not** listed, click the "Request language" button on the main project page
|
||||
to start a new translation project for your language:
|
||||
|
||||
.. image:: images/request-new-language.png
|
||||
|
||||
Before requesting a new language, please first make sure your language is not listed! Keep in
|
||||
mind that variants of your language may exist ("Chinese" versus "Chinese-China") and these
|
||||
variants may meet your needs.
|
||||
|
||||
An edX translation team member will respond to your request within a few days. If your
|
||||
language is approved, you will be the coordinator of the project. You can add additional
|
||||
coordinators, reviewers, and translators as you wish.
|
||||
|
||||
If you request a new language, we ask that you commit to the success of your language's
|
||||
translation project. Particularly, we expect you to be an active translator and work to
|
||||
recruit other translators and reviewers so your language project advances to completion,
|
||||
with all strings translated and reviewed, so that we can publish your work on the edx.org website.
|
||||
|
||||
|
||||
Guidelines for Translators
|
||||
**************************
|
||||
|
||||
Before you dive into translation work, please familiarize yourself with the following
|
||||
3 guidelines:
|
||||
|
||||
* `Ask for Clarification`_
|
||||
* `Working With HTML`_
|
||||
* `Working With Placeholders`_
|
||||
|
||||
|
||||
Ask for Clarification
|
||||
=====================
|
||||
First and foremost, if you are uncertain of how to translate a string, we strongly
|
||||
encourage you to reach out to us and ask for clarification! Please join the
|
||||
`openedx-translation <https://groups.google.com/forum/#!forum/openedx-translation>`_
|
||||
mailing list and make a post. We can help clarify the string, and even add a note
|
||||
clarifying the string, which will help translators working on other language projects.
|
||||
|
||||
|
||||
Working With HTML
|
||||
=================
|
||||
|
||||
Translating strings for a website like edX is more complicated than simply translating sentences
|
||||
from one language to another. Sometimes, sentences (or "strings") will contain
|
||||
`HTML markup tags <https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Introduction>`_. It
|
||||
is very important to understand how to deal with HTML markup.
|
||||
|
||||
Do **not** alter or translate any HTML markup tags.
|
||||
You should translate the text that is between the tags. HTML markup tags begin and end with ``<``
|
||||
and ``>`` characters.
|
||||
|
||||
Spacing is especially important. Adding spaces in an HTML tag (eg changing ``</a>`` to ``</ a>``)
|
||||
will break the website.
|
||||
|
||||
Examples::
|
||||
|
||||
String: "If you have a general question about {platform_name} please email
|
||||
<a href="mailto:{contact_email}">{contact_email}</a>."
|
||||
|
||||
Good translation: "{platform_name}에 대해 일반적인 질문이 있으면
|
||||
<a href="mailto:{contact_email}">{contact_email}</a>로 이메일 주십시요."
|
||||
|
||||
Bad translation: "{platform_name}에 대해 일반적인 질문이 있으면
|
||||
{contact_email}로 이메일 주십시요."
|
||||
|
||||
Please do not remove the HTML tags.
|
||||
|
||||
Bad translation: "{platform_name}에 대해 일반적인 질문이 있으면
|
||||
<a href="흔한:{contact_email}">{contact_email}</a>로 이메일 주십시요."
|
||||
|
||||
Do not translate the HTML tags. Please use the given HTML tags.
|
||||
|
||||
Bad translation: "{platform_name}에 대해 일반적인 질문이 있으면
|
||||
<b>{contact_email}</b>로 이메일 주십시요."
|
||||
|
||||
Do not change the HTML tags to something new. Please use the given HTML tags.
|
||||
|
||||
Bad translation: "{platform_name}에 대해 일반적인 질문이 있으면
|
||||
< a href = " mailto : {contact_email} " > {contact_email} < / a >로 이메일 주십시요."
|
||||
|
||||
Do not add additional spacing to the HTML tags. Please use the given HTML tags.
|
||||
|
||||
|
||||
Working With Placeholders
|
||||
=========================
|
||||
|
||||
Strings in programs sometimes need to have data inserted into them
|
||||
before being displayed to the user. Data placeholders label the places in the string where the
|
||||
data will go. Strings can also have markup like HTML included. It's very important to preserve
|
||||
the placeholders and markup so that the web site will work properly.
|
||||
|
||||
Placeholders come in a few different forms. Often, they are named so that data will be placed into
|
||||
the proper placeholder. Please familiarize yourself with all the different forms to make your
|
||||
translation successful.
|
||||
|
||||
Summary Of Placeholders
|
||||
-----------------------
|
||||
|
||||
+-------------------------+
|
||||
| Placeholder Forms |
|
||||
+=========================+
|
||||
| ``{student_name}`` |
|
||||
+-------------------------+
|
||||
| ``%(student_name)s`` |
|
||||
+-------------------------+
|
||||
| ``<%= student_name %>`` |
|
||||
+-------------------------+
|
||||
|
||||
When dealing with placeholders, you must follow these rules:
|
||||
|
||||
* **Do not** translate the placeholder (for example, changing ``{day}`` to ``{día}``).
|
||||
* **Do not** alter or remove the punctuation of the placeholder string (for example, changing a ``_`` to a ``-``).
|
||||
* **Do not** alter the capitalization of the placeholder string (for example, changing ``{day}`` to ``{Day}``).
|
||||
* **Do not** alter the spacing of the placeholder string (for example, changing ``{day}`` to ``{ day }``).
|
||||
|
||||
Please continue reading for examples of each type of placeholder form inside a string.
|
||||
|
||||
1. Do **not** alter or translate placeholder strings in between curly braces (``{ }``). Strings
|
||||
inside curly braces will be replaced with different strings while the code
|
||||
is executing. Changing the content of the curly braces will cause code to break.
|
||||
|
||||
The placeholder string inside of the braces will give you clues as to what type of data will
|
||||
be presented in the final string. For example, ``{student_name}`` will be replaced with the name
|
||||
of a student, whereas ``{contact_email}`` will be replaced with an email address that users can
|
||||
use to contact us. This will give you some context when you are translating sentences with
|
||||
placeholders.
|
||||
|
||||
Altering the strings includes: changing, removing, or adding punctuation, changing
|
||||
the capitalization, or adding or removing given spacing. So if the placeholder string
|
||||
looks like ``{placeholder_string}``, you should not change it at all, eg ``{Placeholder_String}``,
|
||||
``{placeholder-string}``, ``{ placeholder_string }``, ``{placeholder string}``. All of
|
||||
these changes have the potential to break the software.
|
||||
|
||||
Examples::
|
||||
|
||||
String: "Welcome back {student_name}!"
|
||||
|
||||
Good translation: "¡Bienvenido {student_name}!"
|
||||
|
||||
Bad translation: "¡Bienvenido {nombre de estudiente}!"
|
||||
Do not translate placeholder string - You must use {student_name} exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido {student-name}!"
|
||||
Do not alter the placeholder string punctuation - you must use {student_name} exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido {Student_Name}!"
|
||||
Do not alter the placeholder string capitalization - you must use {student_name} exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido { student_name }!"
|
||||
Do not add additional spacing inside the {} - you must use {student_name} exactly as-is.
|
||||
|
||||
You may rearrange the order of these strings, depending on the requirements of your language.
|
||||
For example, in English the name of the month precedes the day (January 23), wheras in Spanish,
|
||||
the day precedes the month (23 de enero).
|
||||
|
||||
Example::
|
||||
|
||||
String: "Today is {month} {day}."
|
||||
|
||||
Good translation: "Hoy es {day} de {month}."
|
||||
|
||||
|
||||
2. Do **not** alter or translate placeholder strings that begin with a ``%``, then have a string
|
||||
inside parenthesis, and then conclude with an 's' or 'd'. You must preserve the whole form.
|
||||
|
||||
As in the previous example, you must not add, change, or remove punctuation, change capitalization,
|
||||
or add in new spacing.
|
||||
|
||||
Examples::
|
||||
|
||||
String: "Welcome back %(student_name)s!"
|
||||
|
||||
Good translation: "¡Bienvenido %(student_name)s!"
|
||||
|
||||
Bad translation: "¡Bienvenido %(nombre de estudiente)s!"
|
||||
Do not translate placeholder strings - You must use %(student_name)s exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido %(student-name)s!"
|
||||
Do not alter the placeholder string punctuation - you must use %(student_name)s exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido %(Student_Name)s!"
|
||||
Do not alter the placeholder string capitalization - you must use %(student_name)s exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido %( student_name )s!"
|
||||
Do not add additional spacing inside the () - you must use %(student_name)s exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido (student_name)!"
|
||||
Do not remove the '%' or 's' - you must use %(student_name)s exactly as-is.
|
||||
|
||||
You may rearrange the order of these strings, depending on the requirements of your language.
|
||||
For example, in English the name of the month precedes the day (January 23), wheras in Spanish,
|
||||
the day precedes the month (23 de enero).
|
||||
|
||||
Example::
|
||||
|
||||
String: "Today is %(month)s %(day)d."
|
||||
|
||||
Good translation: "Hoy es %(day)d de %(month)s."
|
||||
|
||||
|
||||
3. Do **not** alter or translate placeholder strings that appear within a ``<%= %>`` block. Placeholder
|
||||
strings in this format look like this: ``<%= student_name %>``.
|
||||
|
||||
As in the previous examples, you must not add, change, or remove punctuation, change capitalization,
|
||||
or add in new spacing.
|
||||
|
||||
Examples::
|
||||
|
||||
String: "Welcome back <%= student_name %>!"
|
||||
|
||||
Good translation: "¡Bienvenido <%= student_name %>!"
|
||||
|
||||
Bad translation: "¡Bienvenido <%= nombre de estudiente %>!"
|
||||
Do not translate placeholder strings - You must use <%= student_name %> exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido <%= student-name %>!"
|
||||
Do not alter the placeholder string punctuation - you must use <%= student_name %> exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido <%= Student_Name %>!"
|
||||
Do not alter the placeholder string capitalization - you must use <%= student_name %> exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido < % = student_name % >!"
|
||||
Do not add additional spacing inside the <%= %> - you must use <%= student_name %> exactly as-is.
|
||||
|
||||
Bad translation: "¡Bienvenido <student_name>!"
|
||||
Do not remove or change the '<%=' or '%>' - you must use <%= student_name %> exactly as-is
|
||||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 64 KiB |
@@ -1,56 +0,0 @@
|
||||
.. EdX Dev documentation master file, created by
|
||||
sphinx-quickstart on Fri Nov 2 15:43:00 2012.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
edX Developer's Guide
|
||||
===================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. this is wildly disorganized, and is basically just a dumping ground for
|
||||
.rst files at the moment.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
change_log
|
||||
preface.rst
|
||||
browsers.rst
|
||||
overview.rst
|
||||
extending_platform/index
|
||||
modulestores/index
|
||||
xblocks.rst
|
||||
pavelib.rst
|
||||
public_sandboxes.rst
|
||||
analytics.rst
|
||||
process/index
|
||||
testing/index
|
||||
code-considerations
|
||||
deploy-new-service
|
||||
|
||||
APIs
|
||||
-----
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
djangoapps.rst
|
||||
common-lib.rst
|
||||
experiments.rst
|
||||
|
||||
Internationalization
|
||||
---------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
i18n.rst
|
||||
i18n_translators_guide.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -1,314 +0,0 @@
|
||||
*******************************************
|
||||
LMS module
|
||||
*******************************************
|
||||
|
||||
.. module:: lms
|
||||
|
||||
Branding
|
||||
========
|
||||
|
||||
.. automodule:: branding
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: branding.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Certificates
|
||||
============
|
||||
|
||||
.. automodule:: certificates
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: certificates.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: certificates.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Circuit
|
||||
=======
|
||||
|
||||
.. automodule:: circuit
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: circuit.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: circuit.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Course_wiki
|
||||
===========
|
||||
|
||||
.. automodule:: course_wiki
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Course Nav
|
||||
----------
|
||||
|
||||
.. .. automodule:: course_wiki.course_nav
|
||||
.. :members:
|
||||
.. :show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: course_wiki.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Editors
|
||||
-------
|
||||
|
||||
.. automodule:: course_wiki.editors
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Courseware
|
||||
==========
|
||||
|
||||
.. automodule:: courseware
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Access
|
||||
------
|
||||
|
||||
.. automodule:: courseware.access
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Admin
|
||||
-----
|
||||
|
||||
.. automodule:: courseware.admin
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Courses
|
||||
-------
|
||||
|
||||
.. automodule:: courseware.courses
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Grades
|
||||
------
|
||||
|
||||
.. automodule:: courseware.grades
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: courseware.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Progress
|
||||
--------
|
||||
|
||||
.. automodule:: courseware.progress
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Tabs
|
||||
----
|
||||
|
||||
.. automodule:: courseware.tabs
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Dashboard
|
||||
=========
|
||||
|
||||
.. automodule:: dashboard
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: dashboard.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: dashboard.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Django comment client
|
||||
=====================
|
||||
|
||||
.. automodule:: django_comment_client
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: django_comment_client.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Heartbeat
|
||||
=========
|
||||
|
||||
.. automodule:: heartbeat
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Instructor
|
||||
==========
|
||||
|
||||
.. automodule:: instructor
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: instructor.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Lisenses
|
||||
========
|
||||
|
||||
.. automodule:: licenses
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: licenses.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: licenses.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
LMS migration
|
||||
=============
|
||||
|
||||
.. automodule:: lms_migration
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Migration
|
||||
---------
|
||||
|
||||
.. automodule:: lms_migration.migrate
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Multicourse
|
||||
===========
|
||||
|
||||
.. automodule:: multicourse
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Psychometrics
|
||||
=============
|
||||
|
||||
.. automodule:: psychometrics
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: psychometrics.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Admin
|
||||
-----
|
||||
|
||||
.. automodule:: psychometrics.admin
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Psychoanalyze
|
||||
-------------
|
||||
|
||||
.. automodule:: psychometrics.psychoanalyze
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Static template view
|
||||
====================
|
||||
|
||||
.. automodule:: static_template_view
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: static_template_view.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Static book
|
||||
===========
|
||||
|
||||
.. automodule:: staticbook
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
.. automodule:: staticbook.models
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: staticbook.views
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,84 +0,0 @@
|
||||
*******************************************
|
||||
Xmodule.Modulestore
|
||||
*******************************************
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
.. automodule:: xmodule.modulestore
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Modulestores
|
||||
============
|
||||
|
||||
These implement the :class:`.ModuleStoreRead` and :class:`.ModuleStoreWrite`
|
||||
to provide access to XBlock content.
|
||||
|
||||
.. automodule:: xmodule.modulestore.xml
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.mongo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.split_mongo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Modulestore Helpers
|
||||
-------------------
|
||||
|
||||
These packages provide utilities for easier use of modulestores,
|
||||
and migrating data between modulestores.
|
||||
|
||||
.. automodule:: xmodule.modulestore.search
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.mongoengine_fields
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.split_migrator
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.store_utilities
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Xml Import/Export
|
||||
=================
|
||||
|
||||
These packages focus on importing and exporting xml serialized
|
||||
course content to/from modulestores.
|
||||
|
||||
.. automodule:: xmodule.modulestore.xml_exporter
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.xml_importer
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
|
||||
Miscellaneous
|
||||
=============
|
||||
|
||||
.. automodule:: xmodule.modulestore.django
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.exceptions
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: xmodule.modulestore.inheritance
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
.. _edX Modulestores:
|
||||
|
||||
###########################
|
||||
edX Modulestores
|
||||
###########################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
mixedmodulestore
|
||||
split-mongo
|
||||
@@ -1,12 +0,0 @@
|
||||
#################
|
||||
MixedModuleStore
|
||||
#################
|
||||
|
||||
MixedModuleStore provides a common API for all modulestore functions.
|
||||
|
||||
In addition, MixedModuleStore allows you to select which modulestore a
|
||||
specific course is stored in (XMLModuleStore, DraftModuleStore, Split Mongo)
|
||||
and routes requests for that course to the correct modulestore.
|
||||
|
||||
MixedModuleStore can also handle some conversions from one modulestore to
|
||||
another.
|
||||
@@ -1,43 +0,0 @@
|
||||
#################################
|
||||
Overview of the edX Modulestores
|
||||
#################################
|
||||
|
||||
The edX Platform uses several different modulestores to store course data. Each
|
||||
of these modulestores is in use on edx.org.
|
||||
|
||||
See:
|
||||
|
||||
* `XMLModuleStore`_
|
||||
* `DraftModuleStore`_
|
||||
* :ref:`Split Mongo Modulestore`
|
||||
|
||||
***************
|
||||
XMLModuleStore
|
||||
***************
|
||||
|
||||
The XMLModuleStore was the first modulestore used for the edX Platform.
|
||||
|
||||
XMLModuleStore uses a file system that stores XML-based courses. When the LMS
|
||||
server starts, XMLModuleStore loads every block for every course into memory.
|
||||
|
||||
XMLModuleStore is read-only and does not enable users to change a course
|
||||
without restarting the server.
|
||||
|
||||
*****************
|
||||
DraftModuleStore
|
||||
*****************
|
||||
|
||||
DraftModuleStore was the next generation modulestore and provides greater
|
||||
scalability by allowing random access to course blocks and loading blocks on
|
||||
requests.
|
||||
|
||||
DraftModuleStore allows editing of courses without restarting the server.
|
||||
|
||||
In addition, DraftModuleStore stores a draft version of some types of blocks.
|
||||
|
||||
*****************
|
||||
Split Mongo
|
||||
*****************
|
||||
|
||||
Split Mongo is the newest modulestore. See the :ref:`Split Mongo Modulestore`
|
||||
chapter for more information.
|
||||
@@ -1,164 +0,0 @@
|
||||
.. _Split Mongo Modulestore:
|
||||
|
||||
############################
|
||||
Split Mongo Modulestore
|
||||
############################
|
||||
|
||||
See:
|
||||
|
||||
* `Overview`_
|
||||
* `Split Mongo Data Model`_
|
||||
* `Split Mongo Capabilities`_
|
||||
|
||||
|
||||
************************
|
||||
Overview
|
||||
************************
|
||||
|
||||
*Split Mongo* is the term used for the new edX modulestore. Split Mongo is
|
||||
built on mongoDB. For information about mongoDB, see the `mongoDB website`_.
|
||||
|
||||
The "split" in Split Mongo refers to how a course is split into three types of
|
||||
information:
|
||||
|
||||
* The course identity, referred to as the course index
|
||||
* The course structure
|
||||
* The course content, referred to as XBlock definitions.
|
||||
|
||||
This separation of identity, structure, and content enables course authors to
|
||||
use more advanced capabilities when developing and managing courses.
|
||||
|
||||
.. _mongoDB website: http://www.mongodb.org
|
||||
|
||||
************************
|
||||
Split Mongo Data Model
|
||||
************************
|
||||
|
||||
In the Split Mongo data model, edX courses are split into three collections:
|
||||
|
||||
* `Course Index`_
|
||||
* `Course Structures`_
|
||||
* `XBlock Definitions`_
|
||||
|
||||
=============
|
||||
Course Index
|
||||
=============
|
||||
|
||||
The course index is a dictionary that stores course IDs. Each course ID points
|
||||
to a course structure.
|
||||
|
||||
The course index supports multiple branches of a course. The index can store
|
||||
multiple entries for a course ID, with each entry pointing to a different
|
||||
course structure that corresponds to a different branch.
|
||||
|
||||
As currently implemented, for each course, there is a branch for both the
|
||||
published and draft versions of the course. The published and draft branches of
|
||||
the course point to different structures.
|
||||
|
||||
In the edX Platform:
|
||||
|
||||
* Students using the LMS see and interact with the published version of the
|
||||
course.
|
||||
|
||||
* Course staff using edX Studio make changes to the draft version of the
|
||||
course.
|
||||
|
||||
* When the user changes a the course outline, display names, the course
|
||||
about page, course updates, other course pages, sections or subsections,
|
||||
the draft branch is automatically published; that is, it becomes the
|
||||
published branch.
|
||||
|
||||
* For units and components, changes are saved in the draft branch. The user
|
||||
must publish the unit to change the draft branch to the published branch.
|
||||
When the user begins another set of changes, the draft branch is updated.
|
||||
|
||||
Course Reruns
|
||||
**************
|
||||
|
||||
The edX Platform enables you to rerun a course. When you rerun a course, a new
|
||||
course index is created. The new course index points to the same course
|
||||
structure as the original course index.
|
||||
|
||||
==========================
|
||||
Course Structures
|
||||
==========================
|
||||
|
||||
The course structure defines, or outlines, the content of a course.
|
||||
|
||||
A course structure is made up of blocks in a tree data structure. Blocks are
|
||||
objects in a course, such as the course itself, sections, subsections, and
|
||||
units. A block can reference other blocks; for example, a section references
|
||||
one or more subsections. Each block has a unique ID that is generated by the
|
||||
edX Platform.
|
||||
|
||||
Each block in the course structure points to an XBlock definition. Different
|
||||
blocks, in the same or in different structures, can point to the same
|
||||
definition.
|
||||
|
||||
Course structures, and each block within a structure, are versioned. That is,
|
||||
when a course author changes a course, or a block in the course, a new course
|
||||
structure is saved; the previous course structure, and previous versions of
|
||||
blocks within the structure, remain in the database and are not modified.
|
||||
|
||||
==========================
|
||||
XBlock Definitions
|
||||
==========================
|
||||
|
||||
XBlock definitions contain the content of each block. For some blocks, such as
|
||||
sections and subsections, the definition consists of the block's display name.
|
||||
For components, such as HTML or problem components, the definition also
|
||||
contains the content of the object. A definition can be referenced by multiple
|
||||
blocks.
|
||||
|
||||
XBlock definitions are versioned. That is, when a course author changes
|
||||
content, a new XBlock definition for that object is saved; the previous
|
||||
definition remains in the database and is not modified.
|
||||
|
||||
************************
|
||||
Split Mongo Capabilities
|
||||
************************
|
||||
|
||||
The Split Mongo data model enables the edX Platform to implement advanced
|
||||
content management functionality. Specifically, Split Mongo is designed to
|
||||
enable:
|
||||
|
||||
* `Multiple Course Branches`_
|
||||
* `Versioning`_
|
||||
* `Content Reuse`_
|
||||
|
||||
While these capabilities are not fully implemented in the edX Platform, Split
|
||||
Mongo is designed to allow future enhancements that enable these content
|
||||
management capabilities.
|
||||
|
||||
========================
|
||||
Multiple Course Branches
|
||||
========================
|
||||
|
||||
Split Mongo enables multiple branches of a course. The `course index <Course
|
||||
Index`>_ can have multiple entries for a course ID, each of which points to a
|
||||
different structure.
|
||||
|
||||
The edX Platform currently uses a draft and a published branch for a course.
|
||||
Future enhancements may use other branches.
|
||||
|
||||
============
|
||||
Versioning
|
||||
============
|
||||
|
||||
In Split Mongo, every change to a course or a block within the course is saved,
|
||||
with the time and user recorded.
|
||||
|
||||
Versioning enables future enhancements such as allowing course authors to
|
||||
revert a course or block to a previous version.
|
||||
|
||||
==============
|
||||
Content Reuse
|
||||
==============
|
||||
|
||||
By using pointers to reference XBlock definitions from `course structures
|
||||
<Course Structures>`_, Split Mongo enables content reuse. A single `XBlock
|
||||
definition <XBlock Definition>`_ can be referenced from multiple course
|
||||
structures.
|
||||
|
||||
Future enhancements to the edX Platform can allow course authors to reuse an
|
||||
XBlock in multiple contexts, streamlining course development and maintenance.
|
||||
@@ -1,11 +0,0 @@
|
||||
*******************************************
|
||||
OpaqueKeys
|
||||
*******************************************
|
||||
.. module:: opaque_keys
|
||||
|
||||
OpaqueKeys
|
||||
==========
|
||||
|
||||
.. automodule:: opaque_keys
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,9 +0,0 @@
|
||||
*******************************************
|
||||
Overview
|
||||
*******************************************
|
||||
|
||||
|
||||
This is EdX Dev documentation, mainly extracted from docstrings.
|
||||
Autogenerated by Sphinx from python code.
|
||||
Soon support for JS will be impemented.
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
*******************************************
|
||||
Paver
|
||||
*******************************************
|
||||
|
||||
|
||||
Paver provides a standardised way of managing development and operational tasks in edX.
|
||||
|
||||
To run individual commands, use the following syntax:
|
||||
|
||||
paver <command_name> --option=<option value>
|
||||
|
||||
|
||||
Paver Commands
|
||||
*******************************************
|
||||
|
||||
Paver commands are grouped as follows:
|
||||
|
||||
- Prereqs_ Install all of the prerequisite environments for Python, Node and Ruby
|
||||
- Docs_ Docs is used to build and then optionally display the EdX docs relating to development, authoring and data management
|
||||
- Assets_ Assets will compile Sass (CSS), Coffeescript (Javascript) and XModule assets. Optionally it can call Django’s collectstatic method
|
||||
- `Run Servers`_ Run servers
|
||||
|
||||
|
||||
.. _Prereqs:
|
||||
|
||||
Prereqs
|
||||
=============
|
||||
|
||||
Install all of the prerequisite for Python, Node and Ruby
|
||||
|
||||
**install_prereqs** : installs Ruby, Node and Python requirements
|
||||
|
||||
::
|
||||
|
||||
paver install_prereqs
|
||||
|
||||
..
|
||||
|
||||
|
||||
.. _Docs:
|
||||
|
||||
Docs
|
||||
=============
|
||||
|
||||
Docs is used to build and then optionally display the EdX docs relating to development, authoring and data management
|
||||
|
||||
**build_docs**: Invoke sphinx 'make build' to generate docs.
|
||||
|
||||
*--type=* <dev, author, data> Type of docs to compile
|
||||
|
||||
*--verbose* Display verbose output
|
||||
|
||||
::
|
||||
|
||||
paver build_docs --type=dev --verbose
|
||||
|
||||
..
|
||||
|
||||
|
||||
.. _Assets:
|
||||
|
||||
Assets
|
||||
=============
|
||||
|
||||
Assets will compile Sass (CSS), CoffeeScript (Javascript) and XModule assets. Optionally it can call Django's collectstatic command.
|
||||
|
||||
|
||||
**update_assets**: Compiles Coffeescript, Sass, Xmodule and runs collectstatic
|
||||
|
||||
*system* lms or studio
|
||||
|
||||
*--settings=* Django settings e.g. aws, dev, devstack (the default)
|
||||
|
||||
*--debug* Disable Sass compression
|
||||
|
||||
*--skip-collect* Skip collection of static assets
|
||||
|
||||
::
|
||||
|
||||
paver update_assets lms
|
||||
|
||||
..
|
||||
|
||||
.. _Run Servers:
|
||||
|
||||
Run Servers
|
||||
=============
|
||||
|
||||
**lms**: runs LMS server
|
||||
|
||||
*--settings=* Django settings e.g. aws, dev, devstack (the default)
|
||||
|
||||
*--fast* Skip updating assets
|
||||
|
||||
::
|
||||
|
||||
paver lms --settings=dev
|
||||
|
||||
..
|
||||
|
||||
|
||||
**studio**: runs Studio
|
||||
|
||||
*--settings=* Django settings e.g. aws, dev, devstack (the default)
|
||||
|
||||
*--fast* Skip updating assets
|
||||
|
||||
::
|
||||
|
||||
paver studio --settings=dev
|
||||
|
||||
..
|
||||
|
||||
|
||||
**run_all_servers**: runs lms, cms and celery workers
|
||||
|
||||
*--settings=* Django settings e.g. aws, dev, devstack (the default)
|
||||
|
||||
*--worker_settings=* Django settings for celery workers
|
||||
|
||||
|
||||
::
|
||||
|
||||
paver run_all_servers --settings=dev --worker_settings=celery
|
||||
|
||||
..
|
||||
|
||||
|
||||
**run_celery**: runs celery for specified system
|
||||
|
||||
*--settings=* Environment settings e.g. aws, dev both for LMS and Studio
|
||||
|
||||
*--settings_lms=* Override django settings for LMS e.g. lms.dev
|
||||
|
||||
*--settings_cms=* Override django settings for Studio
|
||||
|
||||
|
||||
::
|
||||
|
||||
paver celery --settings=dev
|
||||
|
||||
..
|
||||
|
||||
**update_db**: runs syncdb and then migrate
|
||||
|
||||
*--settings=* Django settings e.g. aws, dev, devstack (the default)
|
||||
|
||||
::
|
||||
|
||||
paver update_db --settings=dev
|
||||
|
||||
..
|
||||
|
||||
|
||||
**check_settings**: checks settings files
|
||||
|
||||
*system*: System to check (lms or studio)
|
||||
*settings*: Django settings to check.
|
||||
|
||||
::
|
||||
|
||||
paver check_settings lms aws
|
||||
|
||||
..
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.. include:: ../../shared/preface.rst
|
||||
@@ -1,155 +0,0 @@
|
||||
*****************
|
||||
Community Manager
|
||||
*****************
|
||||
|
||||
Community managers handle the first part of the process of responding to pull
|
||||
requests, before they are reviewed by core committers. Community managers are
|
||||
responsible for monitoring the Github project so that they are aware of incoming
|
||||
pull requests. For each pull request, a community manager should:
|
||||
|
||||
#. Read the description of the pull request to understand the idea behind it
|
||||
and what parts of the code it impacts. If the description is absent or
|
||||
unclear, inform the author that the pull request cannot be reviewed until
|
||||
the description is clearer. Guide them to the :doc:`pull request cover letter <cover-letter>`
|
||||
guidelines.
|
||||
|
||||
#. Help the product team evaluate the idea behind the pull request.
|
||||
Is this something that Open edX wants? If you and the
|
||||
product owner(s) all believe that Open edX does not want this pull request,
|
||||
add a comment to the pull request explaining the reasoning behind that
|
||||
decision. Be polite, and remind them that they are welcome to fork the code
|
||||
and run their own fork on their own servers, without needing permission
|
||||
from edX. Try to suggest ways that they can build something that Open edX
|
||||
*does* want: for example, perhaps an API that would allow the contributor
|
||||
to build their own component separately. Then close the pull request.
|
||||
|
||||
#. Check that the author of the pull requests has submitted a
|
||||
`contributor's agreement`_, added name to AUTHORS file, and any other
|
||||
necessary administrivia (our bot will make an automated comment if this is not
|
||||
properly in place). If not, inform author of problems and wait for them to fix it.
|
||||
|
||||
#. Once you’ve verified that the code change is not malicious,
|
||||
run a Jenkins job on the pull request and check the result.
|
||||
If there are failing tests (and they are real failures, not flaky tests),
|
||||
inform the author that the pull request cannot be reviewed until the tests
|
||||
are passing.
|
||||
|
||||
#. When all the tests pass, check the diff coverage and diff quality.
|
||||
If they are too low, inform the author of how to check these metrics,
|
||||
and ask the author to write unit tests to increase coverage and quality
|
||||
Diff quality should be 100%, and diff coverage should be at least 95% unless
|
||||
there are exceptional circumstances.
|
||||
|
||||
#. Skim the contents of the pull request and suggest obvious fixes/improvements
|
||||
to the pull request. Note that this is *not* a thorough code review --
|
||||
this is simply to catch obvious issues and low-hanging fruit.
|
||||
The point is to avoid interrupting core committers for trivial issues.
|
||||
|
||||
#. Ask the author of the pull request for a test plan:
|
||||
once this code is merged, how can we test that it’s working properly?
|
||||
Whichever core committer merges this pull request will need to test it
|
||||
on a staging server before the code is deployed to production, so be sure
|
||||
that the test plan is clear enough for a core committer to follow.
|
||||
|
||||
#. If the PR includes any visual changes, or changes in user interaction,
|
||||
ask the author of the pull request to provide some screenshots.
|
||||
(For interaction changes, GIFs are awesome!) When a core committer starts
|
||||
reviewing the changes, it is often helpful to deploy the pull request to a
|
||||
sandbox server, so that the reviewer can click around and verify that the
|
||||
changes look good.
|
||||
|
||||
#. The core committers will put together a style guide.
|
||||
Pull requests that have visual/UX changes will be expected to respect this
|
||||
style guide -- if they don’t, point the author to the style guide and tell
|
||||
them to resubmit the pull request when it does.
|
||||
|
||||
.. _contributor's agreement: http://code.edx.org/individual-contributor-agreement.pdf
|
||||
|
||||
At this point, the pull request is ready for code review. There are two
|
||||
different options: small PR review and large PR review. A PR is “small” if it
|
||||
can be read and understood in less than 15 minutes, including time spent
|
||||
context-switching, reading the description of the pull request, reading any
|
||||
necessary code context, etc. Typically, “small” PRs consist of fixing typos,
|
||||
improving documentation, adding comments, changing strings to unicode, marking
|
||||
strings that need to be translated, adding tests, and other chores. A “small”
|
||||
pull request doesn’t modify the code that will be run in production in any
|
||||
meaningful way.
|
||||
|
||||
If the pull request is small, it can be reviewed immediately. If the community
|
||||
manager that is handling this pull request feels comfortable doing the code
|
||||
review, then he or she should do so rather than handing it off to a core
|
||||
committer. If not, he or she should move the JIRA ticket for the PR review
|
||||
into the "Awaiting Prioritization" state and add enough detail on the ticket for
|
||||
the product team to understand the size and scope of the changes.
|
||||
Inform the author that it might take a few days for the engineering team to review the PR.
|
||||
|
||||
If the pull request is not small, it will be handled by the full pull request process:
|
||||
|
||||
.. image:: pr-process.png
|
||||
:align: center
|
||||
:alt: A visualization of the pull request process
|
||||
|
||||
The community manager should:
|
||||
|
||||
* Make sure the pull request is ready for Product Review, if that has not yet happened.
|
||||
That means getting enough detail out of the contributor for the product owner
|
||||
to properly do a product review. Once this is done, move the JIRA ticket to the
|
||||
"Product Review" state.
|
||||
|
||||
* If questions arise from product owners during review, work with the contributor to
|
||||
get those questions answered before the next round of review.
|
||||
|
||||
* Once a PR has passed product review, do a first-round review of the PR with the
|
||||
contributor. That is, make sure quality and test coverage is up to par, and that
|
||||
the code generally meets our style guidelines. Once this has happened, move the
|
||||
ticket to the "Awaiting Prioritization" state.
|
||||
|
||||
* At each of these junctures, try to update the author with an estimate of how long
|
||||
the next steps will take. The product team will meet biweekly to review new
|
||||
proposals and prioritize PRs for team review. Direct the contributor to the JIRA ticket
|
||||
as well; the state of the JIRA ticket reflect the above diagram and can give a good
|
||||
sense of where in the process the pull request is.
|
||||
|
||||
* Once a PR has been prioritized for team review, ask the product owner for an estimate
|
||||
of how many sprints it will take for the pull request to be reviewed:
|
||||
if its more than one, try to push back and advocate for the contributor.
|
||||
However, the estimate is ultimately up to the product owner, and if he/she
|
||||
says it will really be more than one sprint, respect that.
|
||||
|
||||
* Add a comment to the pull request and inform the author that the pull request
|
||||
is queued to be reviewed. Give them an estimate of when the pull request
|
||||
will be reviewed: if you’re not sure what to say, tell them it will be in
|
||||
two weeks. If the product owner has estimated that it will take more than
|
||||
one sprint before the pull request can be reviewed, direct the contributor to
|
||||
JIRA to monitor progress.
|
||||
|
||||
For determining which teams that the pull request impacts, use common sense --
|
||||
but in addition, there are a few guidelines:
|
||||
|
||||
* If any SASS files are modified, or any HTML in templates,
|
||||
include the UX (user experience) team.
|
||||
|
||||
* If any settings files or requirements files are modified,
|
||||
include the devops team.
|
||||
|
||||
* If any XModules are modified,
|
||||
include the blades team.
|
||||
|
||||
* If any logging events are modified,
|
||||
include the analytics team.
|
||||
|
||||
* Include the doc team on every contributor pull request that has a user-facing change.
|
||||
|
||||
Once the code review process has started, the community managers are also
|
||||
responsible for keeping the pull request unblocked during the review process. If
|
||||
a pull request has been waiting on a core committer for a few days, a community
|
||||
manager should remind the core committer to re-review the pull request. If a
|
||||
pull request has been waiting on a contributor for a few days, a community
|
||||
manager should add a comment to the pull request, informing the contributor that
|
||||
if they want the pull request merged, they need to address the review comments.
|
||||
If the contributor still has not responded after a few more days, a community
|
||||
manager should close the pull request. Note that if a contributor adds a comment
|
||||
saying something along the lines of “I can’t do this right now, but I’ll come
|
||||
back to it in X amount of time”, that’s fine, and the PR can remain open -- but
|
||||
a community manager should come back after X amount of time, and if the PR still
|
||||
hasn’t been addressed, he or she should warn the contributor again.
|
||||
@@ -1,152 +0,0 @@
|
||||
***********
|
||||
Contributor
|
||||
***********
|
||||
|
||||
Before you make a pull request, it’s a good idea to reach out to the edX
|
||||
developers and the rest of the Open edX community to discuss your ideas. There
|
||||
might well be someone else already working on the same change you want to make,
|
||||
and it’s much better to collaborate than to submit incompatible pull requests.
|
||||
You can `send an email to the mailing list`_, `chat on the IRC channel`_, or
|
||||
`open an issue in our JIRA issue tracker`_. The earlier you start the
|
||||
conversation, the easier it will be to make sure that everyone’s on the right
|
||||
track -- before you spend a lot of time and effort making a pull request.
|
||||
|
||||
.. _send an email to the mailing list: https://groups.google.com/forum/#!forum/edx-code
|
||||
.. _chat on the IRC channel: http://webchat.freenode.net?channels=edx-code
|
||||
.. _open an issue in our JIRA issue tracker: https://openedx.atlassian.net
|
||||
|
||||
If you've got an idea for a new feature or new functionality for an existing feature,
|
||||
and wish to contribute your code upstream, please `start a discussion on JIRA`_
|
||||
(you may first need to `create a free JIRA account`_).
|
||||
Do this by visiting the JIRA website and clicking the "Create" button at the top.
|
||||
Choose the project "Open Source Pull Requests" and the issue type "Feature Proposal";
|
||||
in the description give us as much detail as you can for the feature or functionality
|
||||
you are thinking about implementing. We encourage you to do this before
|
||||
you begin implementing your feature, in order to get valuable feedback from the edX
|
||||
product team early on in your journey and increase the likelihood of a successful
|
||||
pull request.
|
||||
|
||||
.. _start a discussion on JIRA: https://openedx.atlassian.net/secure/Dashboard.jspa
|
||||
.. _create a free JIRA account: https://openedx.atlassian.net/admin/users/sign-up
|
||||
|
||||
It’s also sometimes useful to submit a pull request even before the code is
|
||||
working properly, to make it easier to collect early feedback. To indicate to
|
||||
others that your pull request is not yet in a functional state, just prefix the
|
||||
pull request title with "(WIP)" (which stands for Work In Progress). Please do
|
||||
include a link to a WIP pull request in your JIRA ticket, if you have one.
|
||||
|
||||
Once you’re ready to submit your changes in a pull request, check the following
|
||||
list of requirements to be sure that your pull request is ready to be reviewed:
|
||||
|
||||
#. Prepare a :doc:`pull request cover letter <cover-letter>`. When you open
|
||||
up your pull request, put your cover letter into the "Description" field on Github.
|
||||
|
||||
#. The code should be clear and understandable.
|
||||
Comments in code, detailed docstrings, and good variable naming conventions
|
||||
are expected. The `edx-platform Github wiki`_ contains many great links to
|
||||
style guides for Python, Javascript, and internationalization (i18n) conventions.
|
||||
|
||||
#. The pull request should be as small as possible.
|
||||
Each pull request should encompass only one idea: one bugfix, one feature,
|
||||
etc. Multiple features (or multiple bugfixes) should not be bundled into
|
||||
one pull request. A handful of small pull requests is much better than
|
||||
one large pull request.
|
||||
|
||||
#. Structure your pull request into logical commits.
|
||||
"Fixup" commits should be squashed together. The best pull requests contain
|
||||
only a single, logical change -- which means only a single, logical commit.
|
||||
|
||||
#. All code in the pull request must be compatible with edX's AGPL license.
|
||||
This means that the author of the pull request must sign a `contributor's
|
||||
agreement with edX`_, and all libraries included or referenced in
|
||||
the pull request must have `compatible licenses`_.
|
||||
|
||||
#. All of the tests must pass.
|
||||
If a pull request contains a new feature, it should also contain
|
||||
new tests for that feature. If the pull request fixes a bug, it should
|
||||
also contain a test for that bug to be sure that it stays fixed.
|
||||
(edX’s continuous integration server will verify this for your pull request,
|
||||
and point out any failing tests.)
|
||||
|
||||
#. The author of the pull request should provide a test plan for manually verifying
|
||||
the change in this pull request. The test plan should include details
|
||||
of what should be checked, how to check it, and what the correct behavior
|
||||
should be. When it makes sense to do so, a good test plan includes a tarball
|
||||
of a small edX test course that has a unit which triggers the bug or illustrates
|
||||
the new feature.
|
||||
|
||||
#. For pull requests that make changes to the user interface,
|
||||
please include screenshots of what you changed. Github will allow
|
||||
you to upload images directly from your computer.
|
||||
In the future, the core committers will produce a style guide that
|
||||
contains more requirements around how pages should appear and how
|
||||
front-end code should be structured.
|
||||
|
||||
#. The pull request should contain some documentation for the feature or bugfix,
|
||||
either in a README file or in a comment on the pull request.
|
||||
A well-written description for the pull request may be sufficient.
|
||||
|
||||
#. The pull request should integrate with existing infrastructure as much
|
||||
as possible, rather than reinventing the wheel. In a project as large as
|
||||
Open edX, there are many foundational components that might be hard to find,
|
||||
but it is important not to duplicate functionality, even if small,
|
||||
that already exists.
|
||||
|
||||
#. The author of the pull request should be receptive to feedback and
|
||||
constructive criticism.
|
||||
The pull request will not be accepted until all feedback from reviewers
|
||||
is addressed. Once a core committer has reviewed a pull request from a
|
||||
contributor, no further review is required from the core committer until
|
||||
the contributor has addressed all of the core committer’s feedback:
|
||||
either making changes to the pull request, or adding another comment
|
||||
explaining why the contributor has chosen not make any change
|
||||
based on that feedback.
|
||||
|
||||
It’s also important to realize that you and the core committers may have
|
||||
different ideas of what is important in the codebase. The power and freedom of
|
||||
open source software comes from the fact that you can fork our software and make
|
||||
any modifications that you like, without permission from us; however, the core
|
||||
committers are similarly empowered and free to decide what modifications to pull
|
||||
in from other contributors, and what not to pull in. While your code might work
|
||||
great for you on a small installation, it might not work as well on a large
|
||||
installation, have problems with performance or security, not be compatible with
|
||||
internationalization or accessibility guidelines, and so on. There are many,
|
||||
many reasons why the core committers may decide not to accept your pull request,
|
||||
even for reasons that are unrelated to the quality of your code change. However,
|
||||
if we do reject your pull request, we will explain why we aren’t taking it, and
|
||||
try to suggest other ways that you can accomplish the same result in a way that
|
||||
we will accept.
|
||||
|
||||
Once A PR is Open
|
||||
-----------------
|
||||
|
||||
Once a pull request is open, our faithful robot "Botbro" will open up a JIRA ticket
|
||||
in our system to track review of your pull request. The JIRA ticket is a way for
|
||||
non-engineers (particularly, product owners) to understand your change and prioritize
|
||||
your pull request for team review.
|
||||
|
||||
If you open up your pull request with a solid description, following the
|
||||
:doc:`pull request cover letter <cover-letter>` guidelines, the product owners will be able
|
||||
to quickly understand your change and prioritize it for review. However, they may have
|
||||
some questions about your intention, need, and/or approach that they will ask about
|
||||
on the JIRA ticket. A community manager will ping you on Github to clarify these questions if
|
||||
they arise; you are not required to monitor the JIRA discussion.
|
||||
|
||||
Once the product team has sent your pull request to the engineering teams for review, all
|
||||
technical discussion regarding your change will occur on Github, inline with your code.
|
||||
|
||||
Further Information
|
||||
-------------------
|
||||
For futher information on the pull request requirements, please see the following
|
||||
links:
|
||||
|
||||
* :doc:`../code-considerations`
|
||||
* :doc:`../testing/jenkins`
|
||||
* :doc:`../testing/code-coverage`
|
||||
* :doc:`../testing/code-quality`
|
||||
* `Python Guidelines <https://github.com/edx/edx-platform/wiki/Python-Guidelines>`_
|
||||
* `Javascript Guidelines <https://github.com/edx/edx-platform/wiki/Javascript-Guidelines>`_
|
||||
|
||||
.. _edx-platform Github wiki: https://github.com/edx/edx-platform/wiki#development
|
||||
.. _contributor's agreement with edX: http://code.edx.org/individual-contributor-agreement.pdf
|
||||
.. _compatible licenses: https://github.com/edx/edx-platform/wiki/Licensing
|
||||
@@ -1,93 +0,0 @@
|
||||
**************
|
||||
Core Committer
|
||||
**************
|
||||
|
||||
Core committers are responsible for doing code review on pull requests from
|
||||
contributors, once the pull request has passed through a community manager and
|
||||
been prioritized by a product owner. As much as possible, the code review
|
||||
process should be treated identically to the process of reviewing a pull request
|
||||
from another core committer: we’re all part of the same community. However,
|
||||
there are a few ways that the process is different:
|
||||
|
||||
* The contributor cannot see when conflicts occur in the branch.
|
||||
These conflicts prevent the pull request from being merged,
|
||||
so you should ask the contributor to rebase their pull request,
|
||||
and point them to `the documentation for doing so`_.
|
||||
|
||||
* Jenkins may not run on the contributor’s pull request automatically.
|
||||
Be sure to start new Jenkins jobs for the PR as necessary -- do not approve
|
||||
a pull request unless Jenkins has run, and passed, on the last commit
|
||||
in the pull request. If this contributor has already contributed a few
|
||||
good pull requests, that contributor can be added to the Jenkins whitelist,
|
||||
so that jobs are run automatically.
|
||||
|
||||
* The contributor may not respond to comments in a timely manner.
|
||||
This is not your concern: you can move on to other things while waiting.
|
||||
If there is no response after a few days, a community manager will warn the
|
||||
contributor that if the comments are not addressed, the pull request will
|
||||
be closed. (You can also warn the contributor yourself, if you wish.)
|
||||
Do not close the pull request merely because the contributor hasn’t responded
|
||||
-- if you think the pull request should be closed, inform the
|
||||
community managers, and they will handle it.
|
||||
|
||||
.. _the documentation for doing so: https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request
|
||||
|
||||
Each Scrum team should decide for themselves how to estimate stories related to
|
||||
reviewing external pull requests, and how to claim points for those stories,
|
||||
keeping in mind that an unresponsive contributor may block the story in ways
|
||||
that the team can’t control. When deciding how many contributor pull request
|
||||
reviews to commit to in the upcoming iteration, teams should plan to spend about
|
||||
two hours per week per developer on the team -- larger teams can plan to spend
|
||||
more time than smaller teams. For example, a team with two developers should plan
|
||||
to spend about four hours per week on pull request review, while a team with
|
||||
four developers should plan to spend about eight hours per week on pull request
|
||||
review -- these hours can be spread out among multiple developers, or one
|
||||
developer can do all the review for the whole team in that iteration.
|
||||
However, this is just a guideline: the teams can decide for themselves how
|
||||
many contributor pull request reviews they want to commit to.
|
||||
|
||||
Once a pull request from a contributor passes all required code reviews, a core
|
||||
committer will need to merge the pull request into the project. The core
|
||||
committer who merges the pull request will be responsible for verifying those
|
||||
changes on the staging server prior to release, using the manual test plan provided
|
||||
by the author of the pull request.
|
||||
|
||||
In addition to reviewing contributor requests as part of sprint work, core
|
||||
committers should expect to spend about one hour per week doing other tasks
|
||||
related to the open source community: reading/responding to questions on the
|
||||
mailing list and/or IRC channel, disseminating information about what edX is
|
||||
working on, and so on.
|
||||
|
||||
Review Comments Terminology
|
||||
---------------------------
|
||||
In order to expedite the review process and to have a clear and mutual understanding
|
||||
between reviewers and contributors, the following terminology is strongly suggested
|
||||
when submitting comments on a PR:
|
||||
|
||||
* **Must** - A comment of type "Must" indicates the reviewer feels strongly about
|
||||
their requested change to the code and feels the PR should not be merged unless
|
||||
their concern is satisfactorily addressed.
|
||||
|
||||
* **Opt(ional)** - A comment of type "Optional" indicates the reviewer strongly
|
||||
favors their suggestion, but may be agreeable to the current behavior, especially
|
||||
with a persuasive response.
|
||||
|
||||
* **Nit(pick)** - A comment of type "Nitpick" indicates the reviewer has a minor
|
||||
criticism that *may* not be critical to address, but considers important to share
|
||||
in the given context. Contributors should still seriously consider and weigh these
|
||||
nits and address them in the spirit of maintaining high quality code.
|
||||
|
||||
* **FYI** - A comment of type "FYI" is a related side comment that is
|
||||
informative, but with the intention of having no required immediate action.
|
||||
|
||||
As an example, the following PR comment is clearly categorized as Optional:
|
||||
|
||||
``"Optional: Consider reducing the high degree of connascense in this code by using
|
||||
keyword arguments."``
|
||||
|
||||
**Note:** Unless stated or implied otherwise, all comments are assumed to be of type
|
||||
"Must".
|
||||
|
||||
**Note 2:** It is possible that after further discussion and review, the reviewer
|
||||
chooses to amend their comment, thereby changing its severity to be higher or
|
||||
lower than what was originally set.
|
||||
@@ -1,58 +0,0 @@
|
||||
*************************
|
||||
Pull Request Cover Letter
|
||||
*************************
|
||||
|
||||
When opening up a pull request, please prepare a "cover letter" to place into
|
||||
the "Description" field on Github. A good cover letter concisely answers as
|
||||
many of the following questions as possible. Not all pull requests will have
|
||||
answers to every one of these questions, which is okay!
|
||||
|
||||
* What JIRA ticket does this address (if any)? Please provide a link to the JIRA ticket
|
||||
representing the bug you are fixing or the feature discussion you've already
|
||||
had with the edX product owners.
|
||||
|
||||
* Who have you talked to at edX about this work? Design, architecture, previous PRs,
|
||||
course project manager, IRC, mailing list, etc. Please include links to relevant
|
||||
discussions.
|
||||
|
||||
* Why do you need this change? It's important for us to understand what problem your
|
||||
change is trying to solve, so please describe fully why you feel this change is needed.
|
||||
|
||||
* What components are affected? (LMS, Studio, a specific app in the system, etc)
|
||||
|
||||
* What users are affected? For example, is this a new component intended for use
|
||||
in just one course, or is this a system wide change affecting all edX students?
|
||||
|
||||
* Test instructions for manual testing. When it makes sense to do so, a good test
|
||||
plan includes a tarball of a small test course that has a unit which triggers
|
||||
the bug or illustrates the new feature. Another option would be to provide
|
||||
explicit, numbered steps (ideally with screenshots!) to walk the reviewer
|
||||
through your feature or fix.
|
||||
|
||||
* Please provide screenshots for all user-facing changes.
|
||||
|
||||
* Indicate the urgency of your request. If this is a pull request for a course
|
||||
running or about to run on edx.org, we need to understand your time constraints.
|
||||
Good pieces of information to provide are the course(s) that need this feature
|
||||
and the date that the feature needed by.
|
||||
|
||||
* What are your concerns (the author’s) about the PR? Is there a corner case you
|
||||
don't know how to address or some tests you aren't sure how to add? Please bring
|
||||
these concerns up in your cover letter so we can help!
|
||||
|
||||
|
||||
Example Of A Good PR Cover Letter
|
||||
---------------------------------
|
||||
|
||||
`Pull Request 4675`_ is one of the first edX pull requests to include a cover
|
||||
letter, and it is great! It clearly explains what the bug is, what system is
|
||||
affected (just the LMS), includes a tarball of a course that demonstrates the
|
||||
issue, and provides clear manual testing instructions.
|
||||
|
||||
`Pull Request 4983`_ is another great example. This pull request's cover letter
|
||||
includes before and after screenshots, so the UX team can quickly understand
|
||||
what changes were made and make suggestions. Further, the pull request indicates
|
||||
how to manually test the feature and what date it is needed by.
|
||||
|
||||
.. _Pull Request 4675: https://github.com/edx/edx-platform/pull/4675
|
||||
.. _Pull Request 4983: https://github.com/edx/edx-platform/pull/4983
|
||||
@@ -1,15 +0,0 @@
|
||||
.. _Contributing to Open edX:
|
||||
|
||||
###########################
|
||||
Contributing to Open edX
|
||||
###########################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
contributor
|
||||
cover-letter
|
||||
community-manager
|
||||
product-owner
|
||||
core-committer
|
||||
@@ -1,81 +0,0 @@
|
||||
*****************************
|
||||
Process for Contributing Code
|
||||
*****************************
|
||||
|
||||
Open edX is a massive project, and we would love you to help us build
|
||||
the best online education system in the world -- we can’t do it alone!
|
||||
However, the core committers on the project are also developing features
|
||||
and creating pull requests, so we need to balance reviewing time with
|
||||
development time. To help manage our time and keep everyone as happy as
|
||||
possible, we’ve developed this document that explains what core committers
|
||||
and other contributors can expect from each other. The goals are:
|
||||
|
||||
* Keep pull requests unblocked and flowing as much as possible,
|
||||
while respecting developer time and product owner prioritization.
|
||||
* Maintain a high standard for code quality, while avoiding hurt feelings
|
||||
as much as possible.
|
||||
|
||||
Roles
|
||||
-----
|
||||
|
||||
People play different roles in the pull-request review process. Each role has
|
||||
different jobs and responsibilities:
|
||||
|
||||
:doc:`core-committer`
|
||||
Can commit changes to an Open edX repository. Core committers are
|
||||
responsible for the quality of the code, and for supporting the code in the
|
||||
future. Core committers are also developers in their own right.
|
||||
|
||||
:doc:`product-owner`
|
||||
Prioritizes the work of core committers.
|
||||
|
||||
:doc:`community-manager`
|
||||
Helps keep the community healthy and working smoothly.
|
||||
|
||||
:doc:`contributor`
|
||||
Submits pull requests for eventual committing to an Open edX repository.
|
||||
|
||||
.. note::
|
||||
At the moment, developers who work for edX are core committers, and other
|
||||
developers are contributors. This may change in the future.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. image:: pr-process.png
|
||||
:align: center
|
||||
:alt: A visualization of the pull request process
|
||||
:target: ../_images/pr-process.png
|
||||
|
||||
If you are a :doc:`contributor <contributor>` submitting a pull request, expect that it will
|
||||
take a few weeks before it can be merged. The earlier you can start talking
|
||||
with the rest of the Open edX community about the changes you want to make,
|
||||
before you even start changing code, the better the whole process
|
||||
will go.
|
||||
|
||||
Follow the guidelines in this document for a high-quality pull request: include a detailed
|
||||
description of your pull request when you open it on Github (we recommend using a
|
||||
:doc:`pull request cover letter <cover-letter>` to guide your description),
|
||||
keep the code clear and readable, make sure the tests pass, be responsive to code review comments.
|
||||
Small pull requests are easier to review than large pull requests, so
|
||||
split up your changes into several small pull requests when possible --
|
||||
it will make everything go faster. See the full :doc:`contributor guidelines <contributor>`
|
||||
for details of what to do and what to expect.
|
||||
|
||||
If you are a :doc:`product owner <product-owner>`, treat pull requests
|
||||
from contributors like feature requests from a customer.
|
||||
Keep the lines of communication open -- if there are delays or unexpected
|
||||
problems, add a comment to the pull request informing the author of the
|
||||
pull request of what’s going on. No one likes to feel like they’re being ignored!
|
||||
More details are in the :doc:`product owner guidelines <product-owner>`.
|
||||
|
||||
If you are a :doc:`core committer <core-committer>`, allocate some time
|
||||
in every two-week sprint to review pull requests from other contributors.
|
||||
The community managers will make sure that these pull requests meet a
|
||||
basic standard for quality before asking you spend time reviewing them.
|
||||
More details are in the :doc:`core committer guidelines <core-committer>`.
|
||||
|
||||
Feel free to read the other documentation specific to each individual role in the
|
||||
process, but you don’t need to read everything to get started! If you're not
|
||||
sure where to start, check out the :doc:`contributor <contributor>` documentation. Thanks
|
||||
for helping us grow the project smoothly! :)
|
||||
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 153 KiB |
@@ -1,28 +0,0 @@
|
||||
*************
|
||||
Product Owner
|
||||
*************
|
||||
|
||||
The product owner has two main responsibilities: approving user-facing features
|
||||
and improvements from a product point of view, and prioritizing pull request
|
||||
reviews.
|
||||
|
||||
When a contributor is interested in developing a new feature, or enhancing
|
||||
an existing one, they can engage in a dialogue with the product team about
|
||||
the feature: why it is needed, what does it do, etc. Product owners are expected
|
||||
to fully engage in this process and treat contributors like customers. If
|
||||
the idea is good but the implementation idea is poor, direct them to a better
|
||||
solution. If the feature is not something we can support at this time, provide
|
||||
a detailed explanation of why that is.
|
||||
|
||||
A product owner is responsible for prioritizing pull requests from
|
||||
contributors, and keeping them informed when prioritization slips. Pull
|
||||
requests that are ready to be prioritized in the next sprint will have a
|
||||
"Awaiting Prioritization" label on their JIRA review tickets. At every
|
||||
product review meeting (which should happen each sprint), pull requests awaiting
|
||||
prioritization should either be included in the sprint for the appropriate team
|
||||
as a commitment to get the pull request reviewed, or the
|
||||
product owner must inform the author of the pull request that the pull request
|
||||
is still queued and is not being ignored. Contributors should be treated as
|
||||
customers, and if their pull requests are delayed then they should be informed
|
||||
of that, just as a product owner would inform any customer when that customer’s
|
||||
requests are delayed.
|
||||
@@ -1,160 +0,0 @@
|
||||
####################
|
||||
edX Public Sandboxes
|
||||
####################
|
||||
|
||||
EdX maintains a set of publicly-available sandboxes that allow contributors
|
||||
to interact with the software without having to set up a local development
|
||||
environment.
|
||||
|
||||
* `edx.org Sandbox`_ for those looking to try out the software powering edx.org.
|
||||
|
||||
* `Language Sandboxes`_ for contributors helping to translate Open edX into
|
||||
various languages, who have a need to see translations "in context" - that is,
|
||||
in use on an actual website.
|
||||
|
||||
|
||||
edx.org Sandbox
|
||||
***************
|
||||
This sandbox is intended for those looking to try out the software powering
|
||||
`edx.org <www.edx.org>`_.
|
||||
|
||||
The sandbox provides staff- and student-level access to a copy of the current
|
||||
version of the edx.org website. This sandbox does not allow access to Studio, the
|
||||
course-authoring system.
|
||||
|
||||
Log in by visiting the following URL:
|
||||
|
||||
* `https://www.sandbox.edx.org/ <https://www.sandbox.edx.org/>`_
|
||||
|
||||
You can log in to a staff account using the following credentials:
|
||||
|
||||
* username: staff@example.com
|
||||
* password: edx
|
||||
|
||||
You can log in to a student account using one the following credentials.
|
||||
These user accounts represent students enrolled in the demo course with an
|
||||
audit, honor code, or verified certificate, respectively:
|
||||
|
||||
* username: audit@example.com / honor@example.com / verified@example.com
|
||||
* password: edx
|
||||
|
||||
Language Sandboxes
|
||||
******************
|
||||
|
||||
These sandboxes are intended for translators who have a need to see
|
||||
translations "in context" - that is, in use on an actual website.
|
||||
|
||||
On edx.org, we only pull down reviewed translations from Transifex. See the
|
||||
`translation guidelines <https://github.com/edx/edx-platform/blob/master/docs/en_us/developers/source/i18n_translators_guide.rst#joining-a-review-team>`_
|
||||
for more details.
|
||||
|
||||
To help you review and test, these sandboxes present *all* translations, not
|
||||
just reviewed translations. This means that you may encounter broken pages as
|
||||
you navigate the website. If this happens, it is probably because some of the
|
||||
translated strings in your language have errors such as missing HTML tags or
|
||||
altered {placeholders}. Go through your translations to find and correct these
|
||||
types of translation errors. Use
|
||||
`this guide <https://github.com/edx/edx-platform/blob/master/docs/en_us/developers/source/i18n_translators_guide.rst#guidelines-for-translators>`_
|
||||
to review how to produce non-broken translations.
|
||||
|
||||
Visiting the Sandboxes
|
||||
======================
|
||||
There are two language sandboxes, one for right-to-left, aka "RTL", languages
|
||||
(Arabic, Farsi, Hebrew, and Urdu) and a second one for left-to-right, aka "LTR",
|
||||
languages. Right now, RTL and LTR cannot be supported on the same installation,
|
||||
because the CSS needs to be compiled separately (fixing this issue is a task on our
|
||||
backlog!).
|
||||
|
||||
Note: This is our first deployment of our alpha version of RTL language support! If
|
||||
you have any comments or find any visual bugs, please let us know by posting on the
|
||||
`openedx-translation <https://groups.google.com/forum/#!forum/openedx-translation>`_
|
||||
mailing list.
|
||||
|
||||
LTR and RTL sandboxes are available for both the LMS, or learning managment system (the part
|
||||
of the website that students see) and Studio, the course authoring platform.
|
||||
You can access the LMS at:
|
||||
|
||||
* LTR Sandbox `http://translation-ltr.m.sandbox.edx.org/ <http://translation-ltr.m.sandbox.edx.org/>`_
|
||||
|
||||
* RTL Sandbox `http://translation-rtl.m.sandbox.edx.org/ <http://translation-rtl.m.sandbox.edx.org/>`_
|
||||
|
||||
And you can access Studio at:
|
||||
|
||||
* LTR Sandbox `http://studio.translation-ltr.m.sandbox.edx.org/ <http://studio.translation-ltr.m.sandbox.edx.org/>`_
|
||||
|
||||
* RTL Sandbox `http://studio.translation-rtl.m.sandbox.edx.org/ <http://studio.translation-rtl.m.sandbox.edx.org/>`_
|
||||
|
||||
To access the sandbox servers, you must supply the following username and password:
|
||||
|
||||
* username: edx
|
||||
* password: translation
|
||||
|
||||
Logging In To Sandbox Accounts
|
||||
==============================
|
||||
To log in to the sandbox for a language, you supply the language code in the
|
||||
username as follows:
|
||||
|
||||
* username: LANGUAGE_CODE@example.com
|
||||
* password: edx
|
||||
|
||||
So if you are working on Chinese (China), you'll log in with these credentials:
|
||||
|
||||
* username: zh_CN@example.com
|
||||
* password: edx
|
||||
|
||||
This user account has Course Staff privileges so that you can test Studio and
|
||||
instructor-specific pages in the LMS.
|
||||
|
||||
You can also make new student-level user accounts, which is useful for verifying
|
||||
translations within the registration flow.
|
||||
|
||||
Feel free to test in any way that you want in these sandboxes. Particularly, you are
|
||||
encourage to make new courses, as well as add and delete course content. The sandboxes
|
||||
can be reset if anything breaks, and they are completely disconnected from the
|
||||
production version of the edx.org website.
|
||||
|
||||
|
||||
Caveats and Warnings
|
||||
====================
|
||||
#. These sandboxes will be updated with new translations and the newest version
|
||||
of the edx-platform code about once per week.
|
||||
|
||||
#. We recommend users utilize Chrome or Firefox when using the edX courseware.
|
||||
|
||||
#. When you test, make sure that your browser preference is set to the language
|
||||
you want to test. When you are logged in to the LMS, you can use the
|
||||
language preference widget on the student dashboard page to set or change
|
||||
your language. However, when you are viewing Studio, or if you are not yet
|
||||
logged in to the LMS, the site uses your browser preference to determine
|
||||
what language to display. See `this page on changing your browser's language
|
||||
<http://www.wikihow.com/Change-Your-Browser's-Language>`_ if you need help.
|
||||
|
||||
#. To see an untranslated edX instance in English, which can be helpful to
|
||||
compare to the translated instance, switch your language to English, or
|
||||
visit the `edx.org Sandbox`_.
|
||||
|
||||
#. At the moment, the site does not properly work for languages with an ``@``
|
||||
symbol in the language code, so for now, those languages cannot use the
|
||||
sandbox.
|
||||
|
||||
#. If you have a copy of the edx-platform code, you can generate a list of broken
|
||||
translations in your language by first pulling down the latest translation files::
|
||||
|
||||
tx pull -l LANGUAGE_CODE
|
||||
|
||||
Replace ``LANGUAGE_CODE`` with your code, for example ``zh_CN``.
|
||||
See `this page for instructions on how to configure Transifex <https://github.com/edx/edx-platform/wiki/Internationalization-and-localization>`_.
|
||||
|
||||
Next, run the commands::
|
||||
|
||||
paver i18n_generate
|
||||
i18n_tool validate
|
||||
|
||||
This will generate reports of broken translations in your language. This will not, however,
|
||||
catch HTML tags that are out of order (ex. ``</b> <b>`` instead of ``<b> </b>``).
|
||||
|
||||
|
||||
We hope you find these sandboxes helpful. If you have any questions, comments, or
|
||||
concerns, please give us feedback by posting on the
|
||||
`openedx-translation <https://groups.google.com/forum/#!forum/openedx-translation>`_
|
||||
mailing list. We'd be happy to hear about any improvements you think we could make!
|
||||
@@ -1,11 +0,0 @@
|
||||
*******************************************
|
||||
Sandbox-packages
|
||||
*******************************************
|
||||
.. module:: sandbox-packages
|
||||
|
||||
Loncapa
|
||||
=======
|
||||
|
||||
.. automodule:: loncapa.loncapa_check
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,31 +0,0 @@
|
||||
*******************************************
|
||||
Symmath
|
||||
*******************************************
|
||||
|
||||
.. module:: symmath
|
||||
|
||||
|
||||
Formula
|
||||
=======
|
||||
|
||||
.. automodule:: symmath.formula
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Symmath check
|
||||
=============
|
||||
|
||||
.. automodule:: symmath.symmath_check
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Symmath tests
|
||||
=============
|
||||
|
||||
.. automodule:: symmath.test_formula
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: symmath.test_symmath_check
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -1,26 +0,0 @@
|
||||
*************
|
||||
Code Coverage
|
||||
*************
|
||||
|
||||
We measure which lines of our codebase are covered by unit tests using
|
||||
`coverage.py`_ for Python and `JSCover`_ for Javascript.
|
||||
|
||||
Our codebase is far from perfect, but the goal is to steadily improve our coverage
|
||||
over time. To do this, we wrote a tool called `diff-cover`_ that will
|
||||
report which lines in your branch are not covered by tests, while ignoring
|
||||
other lines in the project that may not be covered. Using this tool,
|
||||
we can ensure that pull requests have a very high percentage of test coverage
|
||||
-- and ideally, they increase the test coverage of existing code, as well.
|
||||
|
||||
To check the coverage of your pull request, just go to the top level of the
|
||||
edx-platform codebase and run::
|
||||
|
||||
$ paver coverage
|
||||
|
||||
This will print a coverage report for your branch. We aim for
|
||||
a coverage report score of 95% or higher. We also encourage you to write
|
||||
acceptance tests as your changes require.
|
||||
|
||||
.. _coverage.py: https://pypi.python.org/pypi/coverage
|
||||
.. _JSCover: http://tntim96.github.io/JSCover/
|
||||
.. _diff-cover: https://github.com/edx/diff-cover
|
||||
@@ -1,44 +0,0 @@
|
||||
************
|
||||
Code Quality
|
||||
************
|
||||
|
||||
In order to keep our code as clear and readable as possible, we use various
|
||||
tools to assess the quality of pull requests:
|
||||
|
||||
* We use the `pep8`_ tool to follow `PEP-8`_ guidelines
|
||||
* We use `pylint`_ for static analysis and uncovering trouble spots in our code
|
||||
|
||||
Our codebase is far from perfect, but the goal is to steadily improve our quality
|
||||
over time. To do this, we wrote a tool called `diff-quality`_ that will
|
||||
only report on the quality violations on lines that have changed in a
|
||||
pull request. Using this tool, we can ensure that pull requests do not introduce
|
||||
any new quality violations -- and ideally, they clean up existing violations
|
||||
in the process of introducing other changes.
|
||||
|
||||
To check the quality of your pull request, just go to the top level of the
|
||||
edx-platform codebase and run::
|
||||
|
||||
$ paver run_quality
|
||||
|
||||
You can also use the `paver run_pep8`` and ``paver run_pylint`` commands to run just pep8 or
|
||||
pylint.
|
||||
|
||||
This will print a report of the quality violations that your branch has made.
|
||||
|
||||
Although we try to be vigilant and resolve all quality violations, some Pylint
|
||||
violations are just too challenging to resolve, so we opt to ignore them via
|
||||
use of a pragma. A pragma tells Pylint to ignore the violation in the given
|
||||
line. An example is::
|
||||
|
||||
self.assertEquals(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
|
||||
|
||||
The pragma starts with a ``#`` two spaces after the end of the line. We prefer
|
||||
that you use the full name of the error (``pylint: disable=unused-argument`` as
|
||||
opposed to ``pylint: disable=W0613``), so it's more clear what you're disabling
|
||||
in the line.
|
||||
|
||||
.. _PEP-8: http://legacy.python.org/dev/peps/pep-0008/
|
||||
.. _pep8: https://pypi.python.org/pypi/pep8
|
||||
.. _coverage.py: https://pypi.python.org/pypi/coverage
|
||||
.. _pylint: http://pylint.org/
|
||||
.. _diff-quality: https://github.com/edx/diff-cover
|
||||
@@ -1,19 +0,0 @@
|
||||
*******
|
||||
Testing
|
||||
*******
|
||||
|
||||
Testing is something that we take very seriously at edX: we even have a
|
||||
"test engineering" team at edX devoted purely to making our testing
|
||||
infrastructure even more awesome.
|
||||
|
||||
This file is currently a stub: to find out more about our testing infrastructure,
|
||||
check out the `testing.md`_ file on Github.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
jenkins
|
||||
code-coverage
|
||||
code-quality
|
||||
|
||||
.. _testing.md: https://github.com/edx/edx-platform/blob/master/docs/en_us/internal/testing.md
|
||||
@@ -1,68 +0,0 @@
|
||||
*******
|
||||
Jenkins
|
||||
*******
|
||||
|
||||
`Jenkins`_ is an open source continuous integration server. edX has a Jenkins
|
||||
installation specifically for testing pull requests to our open source software
|
||||
project, including edx-platform. Before a pull request can be merged, Jenkins
|
||||
must run all the tests for that pull request: this is known as a "build".
|
||||
If even one test in the build fails, then the entire build is considered a
|
||||
failure. Pull requests cannot be merged until they have a passing build.
|
||||
|
||||
Kicking Off Builds
|
||||
==================
|
||||
|
||||
Jenkins has the ability to automatically detect new pull requests and changed
|
||||
pull requests on Github, and it can automatically run builds in response to
|
||||
these events. We have Jenkins configured to automatically run builds for all
|
||||
pull requests from core committers; however, Jenkins will *not* automatically
|
||||
run builds for new contributors, so a community manager will need to manually
|
||||
kick off a build for a pull request from a new contributor.
|
||||
|
||||
The reason for this distinction is a matter of trust. Running a build means that
|
||||
Jenkins will execute all the code in the pull request. A pull request can
|
||||
contain any code whatsoever: if we allowed Jenkins to automatically build every
|
||||
pull request, then a malicious developer could make our Jenkins server do whatever
|
||||
he or she wanted. Before kicking off a build, community managers look at the
|
||||
code changes to verify that they are not malicious; this protects us from nasty
|
||||
people.
|
||||
|
||||
Once a contributor has submitted a few pull requests, they can request to be
|
||||
added to the Jenkins whitelist: this is a special list of people that Jenkins
|
||||
*will* kick off builds for automatically. If the community managers feel that
|
||||
the contributor is trustworthy, then they will grant the request, which will
|
||||
make future development faster and easier for both the contributor and edX. If
|
||||
a contibutor shows that they can not be trusted for some reason, they will be
|
||||
removed from this whitelist.
|
||||
|
||||
Failed Builds
|
||||
=============
|
||||
|
||||
Click on the build to be brought to the build page. You'll see a matrix of blue
|
||||
and red dots; the red dots indicate what section failing tests were present in.
|
||||
You can click on the test name to be brought to an error trace that explains
|
||||
why the tests fail. Please address the failing tests before requesting a new
|
||||
build on your branch. If the failures appear to not have anything to do with
|
||||
your code, it may be the case that the master branch is failing. You can ask
|
||||
your reviewers for advice in this scenario.
|
||||
|
||||
If the build says "Unstable" but passes all tests, you have introduced too many
|
||||
pep8 and pylint violations. Please refer to the documentation for :doc:`code-quality`
|
||||
and clean up the code.
|
||||
|
||||
Successful Builds
|
||||
=================
|
||||
|
||||
If all the tests pass, the "Diff Coverage" and "Diff Quality" reports are
|
||||
generated. Click on the "View Reports" link on your pull request to be brought
|
||||
to the Jenkins report page. In a column on the left side of the page are a few
|
||||
links, including "Diff Coverage Report" and "Diff Quality Report". View each of
|
||||
these reports (making note that the Diff Quality report has two tabs - one for
|
||||
pep8, and one for Pylint).
|
||||
|
||||
Make sure your quality coverage is 100% and your test coverage is at least 95%.
|
||||
Adjust your code appropriately if these metrics are not high enough. Be sure to
|
||||
ask your reviewers for advice if you need it.
|
||||
|
||||
|
||||
.. _Jenkins: http://jenkins-ci.org/
|
||||
@@ -1,256 +0,0 @@
|
||||
.. module:: transcripts
|
||||
|
||||
======================================================
|
||||
Developer’s workflow for the timed transcripts in CMS.
|
||||
======================================================
|
||||
|
||||
:download:`Multipage pdf version of Timed Transcripts workflow. <transcripts_workflow.pdf>`
|
||||
|
||||
:download:`Open office graph version (source for pdf). <transcripts_workflow.odg>`
|
||||
|
||||
:download:`List of implemented acceptance tests. <transcripts_acceptance_tests.odt>`
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
Timed Transcripts functionality is added in separate tab of Video module Editor, that is active by default. This tab is called `Basic`, another tab is called `Advanced` and contains default metadata fields.
|
||||
|
||||
`Basic` tab is a simple representation of `Advanced` tab that provides functionality to speed up adding Video module with transcripts to the course.
|
||||
|
||||
To make more accurate adjustments `Advanced` tab should be used.
|
||||
|
||||
Front-end part of `Basic` tab has 4 editors/views:
|
||||
* Display name
|
||||
* 3 editors for inserting Video URLs.
|
||||
|
||||
Video URL fields might contain 3 kinds of URLs:
|
||||
* **YouTube** link. There are supported formats:
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM&feature=feedrec_grec_index ;
|
||||
* http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/OEoXaMPEzfM ;
|
||||
* http://www.youtube.com/v/OEoXaMPEzfM?fs=1&hl=en_US&rel=0 ;
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM#t=0m10s ;
|
||||
* http://www.youtube.com/embed/OEoXaMPEzfM?rel=0 ;
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM ;
|
||||
* http://youtu.be/OEoXaMPEzfM ;
|
||||
|
||||
* **MP4** video source;
|
||||
* **WEBM** video source.
|
||||
|
||||
Each of these kind of URLs can be specified just **ONCE**. Otherwise, error message occurs on front-end.
|
||||
|
||||
After filling editor **transcripts/check** method will be invoked with the parameters described below (see `API`_). Depending on conditions, that are also described below (see `Commands`_), this method responds with a *command* and front-end renders the appropriate View.
|
||||
Each View can have specific actions. There is a list of supported actions:
|
||||
* Download Timed Transcripts;
|
||||
* Upload Timed Transcripts;
|
||||
* Import Timed Transcripts from YouTube;
|
||||
* Replace edX Timed Transcripts by Timed Transcripts from YouTube;
|
||||
* Choose Timed Transcripts;
|
||||
* Use existing Timed Transcripts.
|
||||
|
||||
All of these actions are handled by 7 API methods described below (see `API`_).
|
||||
|
||||
Because rollback functionality isn't implemented now, after invoking some of the actions user cannot revert changes by clicking button `Cancel`.
|
||||
|
||||
To remove timed transcripts file from the video just go to `Advanced` tab and clear field `sub` then Save changes.
|
||||
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
Command from front-end point of view is just a reference to the needed View with possible actions that user can do depending on conditions described below (See edx-platform/cms/static/js/views/transcripts/message_manager.js:21-29).
|
||||
|
||||
So,
|
||||
* **IF** YouTube transcripts present locally **AND** on YouTube server **AND** both of these transcripts files are **DIFFERENT**, we respond with `replace` command. Ask user to replace local transcripts file by YouTube's ones.
|
||||
* **IF** YouTube transcripts present **ONLY** locally, we respond with `found` command.
|
||||
* **IF** YouTube transcripts present **ONLY** on YouTube server, we respond with `import` command. Ask user to import transcripts file from YouTube server.
|
||||
* **IF** player is in HTML5 video mode. It means that **ONLY** html5 sources are added:
|
||||
* **IF** just 1 html5 source was added or both html5 sources have **EQUAL** transcripts files, then we respond with `found` command.
|
||||
* **OTHERWISE**, when 2 html5 sources were added and founded transcripts files are **DIFFERENT**, we respond with `choose` command. In this case, user should choose which one transcripts file he wants to use.
|
||||
* **IF** we are working with just 1 field **AND** item.sub field **HAS** a value **AND** user fills editor/view by the new value/video source without transcripts file, we respond with `use_existing` command. In this case, user will have possibility to use transcripts file from previous video.
|
||||
* **OTHERWISE**, we will respond with `not_found` command.
|
||||
|
||||
|
||||
Synchronization and Saving workflow
|
||||
====================================
|
||||
|
||||
|
||||
For now saving mechanism works as follows:
|
||||
|
||||
On click `Save` button **ModuleEdit** class (See edx-platform/cms/static/coffee/src/views/module_edit.coffee:83-101) grabs values from all modified metadata fields and sends all this data to the server.
|
||||
|
||||
Because of the fact that Timed Transcripts is module specific functionality, ModuleEdit class is not extended. Instead, to apply all changes that user did in the `Basic` tab, we use synchronization mechanism of TabsEditingDescriptor class. That mechanism provides us possibility to do needed actions on Tab switching and on Save (See edx-platform/cms/templates/widgets/video/transcripts.html).
|
||||
|
||||
On tab switching and when save action is invoked, JavaScript code synchronize collections (Metadata Collection and Transcripts Collection). You can see synchronization logic in the edx-platform/cms/static/js/views/transcripts/editor.js:72-219. In this case, Metadata fields always have the actual data.
|
||||
|
||||
|
||||
Special cases
|
||||
=============
|
||||
|
||||
1. Status message `Timed Transcript Conflict` (Choose) where one of 2 transcripts files should be chosen **-->** click `Save` button without choosing **-->** open Editor **-->** status message `Timed Transcript Found` will be shown and transcripts file will be chosen in random order.
|
||||
|
||||
2. status message `Timed Transcript Conflict` (Choose) where one of 2 transcripts files should be chosen **-->** open `Advanced` tab without choosing **-->** get back to `Basic` tab **-->** status message `Timed Transcript Found` will be shown and transcripts file will be chosen in random order.
|
||||
|
||||
3. The same issues with `Timed Transcript Not Updated` (Use existing).
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
We provide 7 API methods to work with timed transcripts
|
||||
(edx-platform/cms/urls.py:23-29):
|
||||
* transcripts/upload
|
||||
* transcripts/download
|
||||
* transcripts/check
|
||||
* transcripts/choose
|
||||
* transcripts/replace
|
||||
* transcripts/rename
|
||||
* transcripts/save
|
||||
|
||||
**"transcripts/upload"** method is used for uploading SRT transcripts for the
|
||||
HTML5 and YouTube video modules.
|
||||
|
||||
*Method:*
|
||||
POST
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- video_list - list with information about the links currently passed in the editor/view.
|
||||
- file - BLOB file
|
||||
*Response:*
|
||||
HTTP 400
|
||||
or
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
status: 'Success' or 'Error',
|
||||
subs: value of uploaded and saved sub field in the video item.
|
||||
}
|
||||
|
||||
|
||||
**"transcripts/download"** method is used for downloading SRT transcripts for the
|
||||
HTML5 and YouTube video modules.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- subs_id - file name that is used to find transcripts file in the storage.
|
||||
*Response:*
|
||||
HTTP 404
|
||||
or
|
||||
HTTP 200 + BLOB of SRT file
|
||||
|
||||
|
||||
**"transcripts/check"** method is used for checking availability of timed transcripts
|
||||
for the video module.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
*Response:*
|
||||
HTTP 400
|
||||
or
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
command: string with action to front-end what to do and what to show to user,
|
||||
subs: file name of transcripts file that was found in the storage,
|
||||
html5_local: [] or [True] or [True, True],
|
||||
is_youtube_mode: True/False,
|
||||
youtube_local: True/False,
|
||||
youtube_server: True/False,
|
||||
youtube_diff: True/False,
|
||||
current_item_subs: string with value of item.sub field,
|
||||
status: 'Error' or 'Success'
|
||||
}
|
||||
|
||||
|
||||
**"transcripts/choose"** method is used for choosing which transcripts file should be used.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- video_list - list with information about the links currently passed in the editor/view.
|
||||
- html5_id - file name of chosen transcripts file.
|
||||
|
||||
*Response:*
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
status: 'Success' or 'Error',
|
||||
subs: value of uploaded and saved sub field in the video item.
|
||||
}
|
||||
|
||||
|
||||
**"transcripts/replace"** method is used for handling `import` and `replace` commands.
|
||||
Invoking this method starts downloading new transcripts file from YouTube server.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- video_list - list with information about the links currently passed in the editor/view.
|
||||
|
||||
*Response:*
|
||||
HTTP 400
|
||||
or
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
status: 'Success' or 'Error',
|
||||
subs: value of uploaded and saved sub field in the video item.
|
||||
}
|
||||
|
||||
|
||||
**"transcripts/rename"** method is used for handling `use_existing` command.
|
||||
After invoking this method current transcripts file will be copied and renamed to another one with name of current video passed in the editor/view.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- video_list - list with information about the links currently passed in the editor/view.
|
||||
|
||||
*Response:*
|
||||
HTTP 400
|
||||
or
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
status: 'Success' or 'Error',
|
||||
subs: value of uploaded and saved sub field in the video item.
|
||||
}
|
||||
|
||||
|
||||
**"transcripts/save"** method is used for handling `save` command.
|
||||
After invoking this method all changes will be saved that were done before this moment.
|
||||
|
||||
*Method:*
|
||||
GET
|
||||
*Parameters:*
|
||||
- id - location ID of the Xmodule
|
||||
- metadata - new values for the metadata fields.
|
||||
- currents_subs - list with the file names of videos passed in the editor/view.
|
||||
|
||||
*Response:*
|
||||
HTTP 400
|
||||
or
|
||||
HTTP 200 + JSON:
|
||||
.. code::
|
||||
{
|
||||
status: 'Success' or 'Error'
|
||||
}
|
||||
|
||||
|
||||
Transcripts modules:
|
||||
====================
|
||||
|
||||
.. automodule:: contentstore.views.transcripts_ajax
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: contentstore.transcripts_utils
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Video player persists some user preferences between videos and these preferences are stored on server.
|
||||
|
||||
Content for sequential positions is loaded just once on page load and is not updated when the user navigates between sequential positions. So, we doesn't have an actual data from server.
|
||||
To resolve this issue, cookies are used as temporary storage and are removed on page unload.
|
||||
|
||||
How it works:
|
||||
1) On page load: cookies are empty and player get an actual data from server.
|
||||
2) When user change some preferences, new value is stored to cookie;
|
||||
3) If we navigate to another sequential position, video player get an actual data from cookies.
|
||||
4) Close the page: `unload` event fires and we clear our cookies and send user preferences to the server.
|
||||
@@ -1,147 +0,0 @@
|
||||
Integrating XBlocks with edx-platform
|
||||
=====================================
|
||||
|
||||
The edX LMS and Studio have several features that are extensions of the core XBlock
|
||||
libraries (https://xblock.readthedocs.org). These features are listed below.
|
||||
|
||||
* `LMS`_
|
||||
* `Studio`_
|
||||
* `Testing`_
|
||||
* `Deploying your XBlock`_
|
||||
|
||||
LMS
|
||||
---
|
||||
|
||||
Runtime Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
These are properties and methods available on ``self.runtime`` when a view or handler is executed by the LMS.
|
||||
|
||||
* anonymous_student_id: An identifier unique to the student in the particular course
|
||||
that the block is being executed in. The same student in two different courses
|
||||
will have two different ids.
|
||||
|
||||
* publish(block, event_type, event): Emit events to the surrounding system. Events are dictionaries that can contain arbitrary data.
|
||||
XBlocks can publish events by calling ``self.runtime.publish(self, event_type, event)``. The ``event_type`` parameter
|
||||
enables downstream processing of the event since it uniquely identifies the schema. This call will cause the runtime
|
||||
to save the event data in the application event stream. XBlocks should publish events whenever a significant state
|
||||
change occurs. Post-hoc analysis of the event stream can yield insight about how the XBlock is used in the context of
|
||||
the application. Ideally interesting state of the XBlock could be reconstructed at any point in history through
|
||||
careful analysis of the event stream.
|
||||
|
||||
TODO: Link to the authoritive list of event types.
|
||||
|
||||
In the future, these are likely to become more formal XBlock services (one related to users,
|
||||
and the other to event publishing).
|
||||
|
||||
Class Features
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
These are class attributes or functions that can be provided by an XBlock to customize behaviour
|
||||
in the LMS.
|
||||
|
||||
* student_view (XBlock view): This is the view that will be rendered to display the XBlock
|
||||
in the LMS. It will also be used to render the block in "preview" mode in Studio, unless
|
||||
the XBlock also implements author_view.
|
||||
* has_score (class property): True if this block should appear in the LMS progress page.
|
||||
* get_progress (method): See documentation in x_module.py:XModuleMixin.get_progress.
|
||||
* icon_class (class property): This can be one of (``other``, ``video``, or ``problem``), and
|
||||
determines which icon appears in edx sequence headers. There is currently no way to provide
|
||||
a different icon.
|
||||
|
||||
Grading
|
||||
~~~~~~~
|
||||
|
||||
To participate in the course grade, an XBlock should set ``has_score`` to ``True``, and
|
||||
should ``publish`` a ``grade`` event whenever the grade changes. The ``grade`` event is a
|
||||
dictionary of the following form::
|
||||
|
||||
{
|
||||
'value': <number>,
|
||||
'max_value': <number>,
|
||||
'user_id': <number>,
|
||||
}
|
||||
|
||||
The grade event represents a grade of ``value/max_value`` for the current user. The
|
||||
``user_id`` field is optional, the currently logged in user's ID will be used if it is
|
||||
omitted.
|
||||
|
||||
Restrictions
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* A block can't modify the value of any field with a scope where the ``user`` property
|
||||
is ``UserScope.NONE``.
|
||||
|
||||
Studio
|
||||
------
|
||||
|
||||
Class Features
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
* studio_view (XBlock.view): The view used to render an editor in Studio. The editor rendering can be completely different from the LMS student_view, and it is only shown when the author selects "Edit".
|
||||
|
||||
* author_view (XBlock.view): An optional view of the XBlock similar to student_view, but with possible inline editing capabilities. This view differs from studio_view in that it should be as similar to student_view as possible. When previewing XBlocks within Studio, Studio will prefer author_view to student_view.
|
||||
|
||||
* non_editable_metadata_fields (property): A list of ``xblock.fields.Field`` objects that shouldn't be displayed in the default editing view for Studio.
|
||||
|
||||
Restrictions
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* A block can't modify the value of any field with a scope where the ``user`` property
|
||||
is not ``UserScope.NONE``.
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
These instructions are temporary. Once XBlocks are fully supported by edx-platform
|
||||
(both the LMS and Studio), installation and testing will be much more straightforward.
|
||||
|
||||
To enable an XBlock for testing in your devstack (https://github.com/edx/configuration/wiki/edX-Developer-Stack):
|
||||
|
||||
#. Install your block::
|
||||
|
||||
$ vagrant ssh
|
||||
vagrant@precise64:~$ sudo -u edxapp /edx/bin/pip.edxapp install /path/to/your/block
|
||||
|
||||
#. Enable the block
|
||||
|
||||
#. In ``edx-platform/lms/envs/common.py``, uncomment::
|
||||
|
||||
# from xmodule.x_module import prefer_xmodules
|
||||
# XBLOCK_SELECT_FUNCTION = prefer_xmodules
|
||||
|
||||
#. In ``edx-platform/cms/envs/common.py``, uncomment::
|
||||
|
||||
# from xmodule.x_module import prefer_xmodules
|
||||
# XBLOCK_SELECT_FUNCTION = prefer_xmodules
|
||||
|
||||
#. In ``edx-platform/cms/envs/common.py``, change::
|
||||
|
||||
'ALLOW_ALL_ADVANCED_COMPONENTS': False,
|
||||
|
||||
to::
|
||||
|
||||
'ALLOW_ALL_ADVANCED_COMPONENTS': True,
|
||||
|
||||
#. Add the block to your courses' advanced settings in Studio
|
||||
|
||||
#. Log in to Studio, and open your course
|
||||
#. Settings -> Advanced Settings
|
||||
#. Change the value for the key ``"advanced_modules"`` to ``["your-block"]``
|
||||
|
||||
#. Add your block into your course
|
||||
|
||||
#. Edit a unit
|
||||
#. Advanced -> your-block
|
||||
|
||||
Note the name ``your-block`` used in Studio must exactly match the key you used to add your
|
||||
block to your ``setup.py`` ``entry_points`` list (if you are still discovering Xblocks and simply used the ``startnew.py`` script as described at https://github.com/edx/XBlock/blob/master/doc/getting_started.rst , look in the ``setup.py`` file that was created)
|
||||
|
||||
|
||||
Deploying your XBlock
|
||||
---------------------
|
||||
|
||||
To deploy your block to your own hosted version of edx-platform, you need to install it
|
||||
into the virtualenv that the platform is running out of, and add to the list of ``ADVANCED_COMPONENT_TYPES``
|
||||
in ``edx-platform/cms/djangoapps/contentstore/views/component.py``.
|
||||
@@ -1,181 +0,0 @@
|
||||
*******************************************
|
||||
Xmodule
|
||||
*******************************************
|
||||
|
||||
.. module:: xmodule
|
||||
|
||||
Abtest
|
||||
======
|
||||
|
||||
.. automodule:: xmodule.abtest_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Back compatibility
|
||||
==================
|
||||
|
||||
.. automodule:: xmodule.backcompat_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Capa
|
||||
====
|
||||
|
||||
.. automodule:: xmodule.capa_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Course
|
||||
======
|
||||
|
||||
.. automodule:: xmodule.course_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Discussion
|
||||
==========
|
||||
|
||||
.. automodule:: xmodule.discussion_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Editing
|
||||
=======
|
||||
|
||||
.. automodule:: xmodule.editing_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Error
|
||||
=====
|
||||
|
||||
.. automodule:: xmodule.error_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Error tracker
|
||||
=============
|
||||
|
||||
.. automodule:: xmodule.errortracker
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
.. automodule:: xmodule.exceptions
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Graders
|
||||
=======
|
||||
|
||||
.. automodule:: xmodule.graders
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Hidden
|
||||
======
|
||||
|
||||
.. automodule:: xmodule.hidden_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Html checker
|
||||
============
|
||||
|
||||
.. automodule:: xmodule.html_checker
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Html
|
||||
====
|
||||
|
||||
.. automodule:: xmodule.html_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
LTI
|
||||
===
|
||||
|
||||
.. automodule:: xmodule.lti_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Mako
|
||||
====
|
||||
|
||||
.. automodule:: xmodule.mako_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Progress
|
||||
========
|
||||
|
||||
.. automodule:: xmodule.progress
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Sequence
|
||||
========
|
||||
|
||||
.. automodule:: xmodule.seq_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Stringify
|
||||
=========
|
||||
|
||||
.. automodule:: xmodule.stringify
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Template
|
||||
========
|
||||
|
||||
.. automodule:: xmodule.template_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Templates
|
||||
=========
|
||||
|
||||
.. automodule:: xmodule.templates
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Vertical
|
||||
========
|
||||
|
||||
.. automodule:: xmodule.vertical_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Video
|
||||
=====
|
||||
.. include:: video_player.rst
|
||||
.. automodule:: xmodule.video_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Word Cloud
|
||||
==========
|
||||
|
||||
.. automodule:: xmodule.word_cloud_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
X
|
||||
=
|
||||
|
||||
.. automodule:: xmodule.x_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Xml
|
||||
===
|
||||
|
||||
.. automodule:: xmodule.xml_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||