-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add open edx event guide (#80)
Add guide for new contributors to the Open edX Events library following new standards for Sphinx documentation.
- Loading branch information
1 parent
b3548b0
commit 20ecb70
Showing
17 changed files
with
547 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
Openedx Hooks Extension Framework | ||
================================= | ||
|
||
To sustain the growth of the Open edX ecosystem, the business rules of the | ||
platform must be open for extension following the open-closed principle. This | ||
framework allows developers to do just that without needing to fork and modify | ||
the main Open edX platform. | ||
|
||
Context | ||
------- | ||
|
||
Hooks are predefined places in the Open edX project core where externally defined | ||
functions can take place. In some cases, those functions can alter what the user | ||
sees or experiences in the platform. Other cases are informative only. All cases | ||
are meant to be extended using Open edX plugins and configuration. | ||
|
||
Hooks can be of two types, events and filters. Events are in essence signals, in | ||
that they are sent in specific application places and whose listeners can extend | ||
functionality. functionality. On the other hand Filters can be used to act on data before | ||
it is put back in the original application flow. In order to allow | ||
extension developers to use the Events and Filters definitions on their plugins, | ||
both kinds of hooks are defined in lightweight external libraries. | ||
|
||
* `openedx-filters`_ | ||
* `openedx-events`_ | ||
|
||
Hooks are designed with stability in mind. The main goal is that developers can | ||
use them to change the functionality of the platform as needed and still be able | ||
to migrate to newer open releases with very little to no development effort. In | ||
the case of the events, this is detailed in the `versioning ADR`_ and the | ||
`payload ADR`_. | ||
|
||
A longer description of the framework and its history can be found in `OEP 50`_. | ||
|
||
.. _OEP 50: https://open-edx-proposals.readthedocs.io/en/latest/oep-0050-hooks-extension-framework.html | ||
.. _versioning ADR: https://github.com/eduNEXT/openedx-events/blob/main/docs/decisions/0002-events-naming-and-versioning.rst | ||
.. _payload ADR: https://github.com/eduNEXT/openedx-events/blob/main/docs/decisions/0003-events-payload.rst | ||
.. _openedx-filters: https://github.com/eduNEXT/openedx-filters | ||
.. _openedx-events: https://github.com/eduNEXT/openedx-events | ||
|
||
On the technical side events are implemented through django signals which makes | ||
them run in the same python process as the service where this library is installed. | ||
Furthermore, events block the running process. Listeners of an event are encouraged | ||
to monitor the performance or use alternative arch patterns such as receiving the | ||
event and defer to launching async tasks than do the slow processing. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
Concepts | ||
======== | ||
|
||
.. toctree:: | ||
:maxdepth: 1 | ||
:caption: Contents: | ||
|
||
hooks-extension-framework |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
How to add an Open edX Event to a service | ||
========================================= | ||
|
||
The next step after creating your first event in the Open edX Events library is to trigger the event in the service | ||
you implemented it for. Here is a checklist of what we've done so far when including a new event to a service: | ||
|
||
- Add the openedx-events library to the service project. | ||
- Import the events' data and definition into the place where the event be triggered. Remember the event's purpose when | ||
choosing a place to send the new event. | ||
- Add inline documentation with the ``event_implemented_name``. This matches the ``event_name`` in line documentation from the library. | ||
- Refer to the service project's contribution guidelines and follow the instructions. Then, open a new pull request! | ||
|
||
Consider the addition of the event ``STUDENT_REGISTRATION_COMPLETED`` to edx-platform as an example: | ||
|
||
.. code-block:: python | ||
# Location openedx/core/djangoapps/user_authn/views/register.py | ||
# .. event_implemented_name: COURSE_ENROLLMENT_CREATED | ||
COURSE_ENROLLMENT_CREATED.send_event( | ||
enrollment=CourseEnrollmentData( | ||
user=UserData( | ||
pii=UserPersonalData( | ||
username=user.username, | ||
email=user.email, | ||
name=user.profile.name, | ||
), | ||
id=user.id, | ||
is_active=user.is_active, | ||
), | ||
course=course_data, | ||
mode=enrollment.mode, | ||
is_active=enrollment.is_active, | ||
creation_date=enrollment.created, | ||
) | ||
) | ||
If you want to know more about how the integration of the first events' batch went, check out the `PR 28266`_. | ||
|
||
.. _PR 28266: https://github.com/openedx/edx-platform/pull/28266 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Using the Open edX Event bus | ||
============================ | ||
|
||
After creating a new Open edX Event, you might need to send it across services | ||
instead of just within the same process. For this kind of use-cases, you might want | ||
to use the Open edX Event Bus. Here, we list useful information about | ||
adding a new event to the event bus: | ||
|
||
- `How to start using the Event Bus`_ | ||
- `Sample pull request adding new Open edX Events to the Event Bus` | ||
|
||
|
||
.. _How to start using the Event Bus: https://openedx.atlassian.net/wiki/spaces/AC/pages/3508699151/How+to+start+using+the+Event+Bus | ||
.. _Sample pull request adding new Open edX Events to the Event Bus: https://github.com/openedx/edx-platform/pull/31350 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
How to create a new Open edX Event | ||
================================== | ||
|
||
The mechanisms implemented by the Open edX Events library are supported and maintained by the Open edX community. | ||
Therefore, we've put together a guide on how to add a new event to the library so future contributions are effective. | ||
|
||
|
||
1. Propose the new event to the community | ||
----------------------------------------- | ||
|
||
When creating a new event, you must justify its implementation. For example, you could create a post in Discuss, | ||
send a message through slack or open a new issue in the library repository listing your use cases for it. Or even, | ||
if you have time, you could accompany your proposal with the implementation of the event to illustrate its behavior. | ||
|
||
.. note:: | ||
There is an open discussion about whether organization scoped events would also exist in openedx-events, | ||
in which case this step would be optional. See issue `Organization scoped events <https://github.com/openedx/openedx-events/issues/196>`_. | ||
|
||
2. Place your event in an architecture subdomain | ||
------------------------------------------------- | ||
|
||
As specified in the Architectural Decisions Record (ADR) events naming and versioning, the event definition needs an Open edX Architecture | ||
Subdomain for: | ||
|
||
- The name of the event: ``{Reverse DNS}.{Architecture Subdomain}.{Subject}.{Action}.{Major Version}`` | ||
- The package name where the definition will live, eg. ``learning/`` or ``content_authoring/``. | ||
|
||
For those reasons, after studying your new event purpose, you must place it in one of the subdomains already in use, or introduce a new subdomain: | ||
|
||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| Subdomain name | Description | | ||
+===================+====================================================================================================+ | ||
| Content Authoring | Allows educators to create, modify, package, annotate (tag), and share learning content. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| Learning | Allows learners to consume content and perform actions in a learning activity on the platform. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
|
||
New subdomains may require some discussion, because there does not yet exist and agreed upon set on subdomains. So we encourage you to start the conversation | ||
as soon as possible through any of the communication channels available. | ||
|
||
Refer to `edX DDD Bounded Contexts <https://openedx.atlassian.net/l/cp/vf8XjRiX>`_ confluence page for more documentation on domain-driven design in the Open edX project. | ||
|
||
3. Create the data attributes for the event (OEP-49) | ||
---------------------------------------------------- | ||
|
||
Events send `data attributes <https://open-edx-proposals.readthedocs.io/en/latest/architectural-decisions/oep-0049-django-app-patterns.html#data-py>`_ when triggered. Therefore, when designing your new event definition you must | ||
decide if an existent data class works for your use case or you must create a new one. If the answer is the latter, then try to answer: | ||
|
||
- Which attributes of the object are the most relevant? | ||
- Which type are they? | ||
- Are any of them optional/required? | ||
|
||
And with that information, create the new class justifying each decision. The class created in this step must comply | ||
with: | ||
|
||
- It should be created in the `data.py` file, as described in the OEP-49, in the corresponding architectural subdomain. Refer to Naming Conventions ADR for more | ||
on events subdomains. | ||
- It should follow the naming conventions used across the other events definitions. | ||
|
||
Consider the user data representation as an example: | ||
|
||
.. code-block:: python | ||
@attr.s(frozen=True) | ||
class CourseData: | ||
""" | ||
Attributes defined for Open edX Course Overview object. | ||
Arguments: | ||
course_key (str): identifier of the Course object. | ||
display_name (str): display name associated with the course. | ||
start (datetime): start date for the course. | ||
end (datetime): end date for the course. | ||
""" | ||
course_key = attr.ib(type=CourseKey) | ||
display_name = attr.ib(type=str, factory=str) | ||
start = attr.ib(type=datetime, default=None) | ||
end = attr.ib(type=datetime, default=None) | ||
@attr.s(frozen=True) | ||
class CourseEnrollmentData: | ||
""" | ||
Attributes defined for Open edX Course Enrollment object. | ||
Arguments: | ||
user (UserData): user associated with the Course Enrollment. | ||
course (CourseData): course where the user is enrolled in. | ||
mode (str): course mode associated with the course. | ||
is_active (bool): whether the enrollment is active. | ||
creation_date (datetime): creation date of the enrollment. | ||
created_by (UserData): if available, who created the enrollment. | ||
""" | ||
user = attr.ib(type=UserData) | ||
course = attr.ib(type=CourseData) | ||
mode = attr.ib(type=str) | ||
is_active = attr.ib(type=bool) | ||
creation_date = attr.ib(type=datetime) | ||
created_by = attr.ib(type=UserData, default=None) | ||
4. Create the event definition | ||
------------------------------ | ||
|
||
Open edX Events are instances of the class OpenEdxPublicSignal, this instance represents the event definition that | ||
specifies: | ||
|
||
- The event type which should follow the conventions in the Naming Conventions ADR. | ||
- The events' payload, here you must use the class you decided on before. | ||
|
||
The definition created in this step must comply with: | ||
|
||
- It should be created in the `signals.py` file in the corresponding subdomain. Refer to Naming Conventions ADR for more | ||
on events subdomains. | ||
- It should follow the naming conventions specified in Naming Conventions ADR. | ||
- It must be documented using in-line documentation with at least: `event_type`, `event_name`, `event_description` and | ||
`event_data`: | ||
|
||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| Annotation | Description | | ||
+===================+====================================================================================================+ | ||
| event_type | Identifier across services of the event. Should follow the events naming conventions. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| event_name | Name of the variable storing the event instance. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| event_description | General description which includes when the event should be emitted. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
| event_data | What type of class attribute the event sends. | | ||
+-------------------+----------------------------------------------------------------------------------------------------+ | ||
|
||
Consider the following example: | ||
|
||
.. code-block:: python | ||
# Location openedx_events/learning/signals.py | ||
# .. event_type: org.openedx.learning.course.enrollment.created.v1 | ||
# .. event_name: COURSE_ENROLLMENT_CREATED | ||
# .. event_description: emitted when the user's enrollment process is completed. | ||
# .. event_data: CourseEnrollmentData | ||
COURSE_ENROLLMENT_CREATED = OpenEdxPublicSignal( | ||
event_type="org.openedx.learning.course.enrollment.created.v1", | ||
data={ | ||
"enrollment": CourseEnrollmentData, | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,11 @@ | ||
How-tos | ||
####### | ||
|
||
.. toctree:: | ||
:maxdepth: 1 | ||
:caption: Contents: | ||
|
||
creating-new-events | ||
adding-events-to-a-service | ||
adding-events-to-event-bus | ||
using-events |
Oops, something went wrong.