Skip to content

Commit

Permalink
[RE-[#105] Update documentation on hooks and functions
Browse files Browse the repository at this point in the history
  • Loading branch information
javrasya committed Nov 17, 2019
1 parent c2d01cd commit d2b8173
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 147 deletions.
42 changes: 35 additions & 7 deletions README.rst
Expand Up @@ -14,7 +14,6 @@
.. |Quality Status| image:: https://api.codacy.com/project/badge/Grade/c3c73d157fe045e6b966d8d4416b6b17
:alt: Codacy Badge
:target: https://app.codacy.com/app/javrasya/django-river?utm_source=github.com&utm_medium=referral&utm_content=javrasya/django-river&utm_campaign=Badge_Grade_Dashboard


.. |Timeline| image:: https://cloud.githubusercontent.com/assets/1279644/9934893/921b543a-5d5c-11e5-9596-a5e067db79ed.png

Expand Down Expand Up @@ -116,11 +115,11 @@ create your functions and also the hooks to a certain events by just creating fe
For all these event types, you can create a hooking with a given function which is created separately and preliminary than the hookings for all the workflow objects you have
or you will possible have, or for a specific workflow object. You can also hook up before or after the events happen.

Create Function
^^^^^^^^^^^^^^^
1. Create Function
^^^^^^^^^^^^^^^^^^

This will be the description of your functions. So you define them once and you can use them with multiple hooking up. Just go to `/admin/river/function/` admin page
and create your functions there. `django-river` function admin support python code highlights.
and create your functions there. ``django-river`` function admin support python code highlights.

.. code:: python
Expand All @@ -134,17 +133,46 @@ and create your functions there. `django-river` function admin support python co
Here is an example function;

.. code:: python
from datetime import datetime
def handle(context):
print(datetime.now())
print(context)
`django-river` will pass a `context` down to your function in respect to in order for you to know why the function is triggered. And the `context` will look different for
different type of events
**Important:** **YOUR FUNCTION SHOULD BE NAMED AS** ``handle``. Otherwise ``django-river`` won't execute your function.

``django-river`` will pass a ``context`` down to your function in order for you to know why the function is triggered or for which object or so. And the ``context`` will look different for
different type of events. Please see detailed `context documentation`_ to know more on what you would get from context in your functions.

You can find an `advance function example`_ on the link.

.. _`context documentation`: https://django-river.readthedocs.io/en/latest/hooking/function.html#context-parameter
.. _`advance function example`: https://django-river.readthedocs.io/en/latest/hooking/function.html#example-function

2. Hook It Up
^^^^^^^^^^^^^

The hookings in ``django-river`` can be created both specifically for a workflow object or for a whole workflow. ``django-river`` comes with some model objects and admin interfaces which you can use
to create the hooks.

* To create one for whole workflow regardless of what the workflow object is, go to
* ``/admin/river/onapprovedhook/`` to hook up to an approval
* ``/admin/river/ontransithook/`` to hook up to a transition
* ``/admin/river/oncompletehook/`` to hook up to the completion of the workflow

* To create one for a specific workflow object you should use the admin interface for the workflow object itself. One amazing feature of ``django-river`` is now that it creates a default admin interface
with the hookings for your workflow model class. If you have already defined one, ``django-river`` enriches your already defined admin with the hooking section. It is default enabled. To disable it
just define ``RIVER_INJECT_MODEL_ADMIN`` to be ``False`` in the ``settings.py``.


**Note:** They can programmatically be created as well since they are model objects. If it is needed to be at workflow level, just don't provide the workflow object column. If it is needed
to be for a specific workflow object then provide it.

Here are the list of hook model object

* OnApprovedHook
* OnTransitHook
* OnCompleteHook


Contribute
Expand Down
12 changes: 6 additions & 6 deletions docs/authorization.rst
Expand Up @@ -7,19 +7,19 @@ by any of them is entitled to see and approve the approvals.

Permission Based Authorization
""""""""""""""""""""""""""""""
Multiple permission can be specified on the `transition approval metadata` admin page and `django-river` will allow only the users who have the given permission.
Given multiple permissions are issued in `OR` fashion meaning that it is enough to have one of the given permissions to be authorized for the user. This can be
Multiple permission can be specified on the `transition approval metadata` admin page and ``django-river`` will allow only the users who have the given permission.
Given multiple permissions are issued in ``OR`` fashion meaning that it is enough to have one of the given permissions to be authorized for the user. This can be
configurable on the admin page provided by `django-river`

User Group Based Authorization
""""""""""""""""""""""""""""""
Multiple user group can be specified on the `transition approval metadata` admin page and `django-river` will allow only the users who are in the given user groups.
Like permission based authorization, given multiple user groups are issued in `OR` fashion meaning that it is enough to be in one of the given user groups to be
Multiple user group can be specified on the `transition approval metadata` admin page and ``django-river`` will allow only the users who are in the given user groups.
Like permission based authorization, given multiple user groups are issued in ``OR`` fashion meaning that it is enough to be in one of the given user groups to be
authorized for the user.This can be configurable on the admin page provided by `django-river`

User Based Authorization
""""""""""""""""""""""""
Only one specific user can be assigned and no matter what permissions the user has or what user groups the user is in, the user will be authorized. Unlike the other
methods, `django-river` doesn't provide an admin interface for that. But this can be handled within the repositories that is using `django-river`. The way how to do
this is basically setting the `transactioner` column of the related `TransitionApproval` object as the user who is wanted to be authorized on this approval either
methods, ``django-river`` doesn't provide an admin interface for that. But this can be handled within the repositories that is using `django-river`. The way how to do
this is basically setting the ``transactioner`` column of the related ``TransitionApproval`` object as the user who is wanted to be authorized on this approval either
programmatically or through a third party admin page on this model.
148 changes: 148 additions & 0 deletions docs/hooking/function.rst
@@ -0,0 +1,148 @@
.. _hooking_function_guide:

Functions
=========

Functions are the description in ``Python`` of what you want to do on certain events happen. So you define them once and you can use them
with multiple hooking up. Just go to `/admin/river/function/` admin page and create your functions there.`django-river` function admin support
python code highlighting as well if you enable the ``codemirror2`` app. Don't forget to collect statics for production deployments.


.. code:: python
INSTALLED_APPS=[
...
codemirror2
river
...
]
Here is an example function;

.. code:: python
from datetime import datetime
def handle(context):
print(datetime.now())
**Important:** **YOUR FUNCTION SHOULD BE NAMED AS** ``handle``. Otherwise ``django-river`` won't execute your function.

Context Parameter
-----------------

`django-river` will pass a ``context`` down to your function in order for you to know why the function is triggered or for which object or so. And the `context`
will look different for different type of events. But it also has some common parts for all the events. Let's look at how it looks;


``context.hook ->>``

+---------------------+--------+--------------------+---------------------------------------------------------+
| Key | Type | Format | Description |
+=====================+========+====================+=========================================================+
| type | String | | * on-approved | | The event type that is hooked up. The payload will |
| | | | * on-transit | | likely differ according to this value |
| | | | * on-complete | |
+---------------------+--------+--------------------+---------------------------------------------------------+
| when | String | | * BEFORE | | Whether it is hooked right before the event happens |
| | | | * AFTER | | or right after |
+---------------------+--------+--------------------+---------------------------------------------------------+
| payload | dict | | | This is the context content that will differ for each |
| | | | | event type. The information that can be gotten from |
| | | | | payload is describe in the table below |
+---------------------+--------+--------------------+---------------------------------------------------------+

Context Payload
---------------

On-Approved Event Payload
^^^^^^^^^^^^^^^^^^^^^^^^^
+---------------------+------------------+---------------------------------------------------------+
| Key | Type | Description |
+=====================+==================+=========================================================+
| workflow | Workflow Model | The workflow that the transition currently happening |
+---------------------+------------------+---------------------------------------------------------+
| workflow_object | | Your Workflow | | The workflow object of the model that has the state |
| | | Object | | field in it |
+---------------------+------------------+---------------------------------------------------------+
| transition_approval | | Transition | | The approval object that is currently approved which |
| | | Approval | | contains the information of the transition(meta) as |
| | | | well as who approved it etc. |
+---------------------+------------------+---------------------------------------------------------+

On-Transit Event Payload
^^^^^^^^^^^^^^^^^^^^^^^^
+---------------------+------------------+---------------------------------------------------------+
| Key | Type | Description |
+=====================+==================+=========================================================+
| workflow | Workflow Model | The workflow that the transition currently happening |
+---------------------+------------------+---------------------------------------------------------+
| workflow_object | | Your Workflow | | The workflow object of the model that has the state |
| | | Object | | field in it |
+---------------------+------------------+---------------------------------------------------------+
| transition_approval | | Transition | | The last transition approval object which contains |
| | | Approval | | the information of the transition(meta) as well as |
| | | | who last approved it etc. |
+---------------------+------------------+---------------------------------------------------------+


On-Complete Event Payload
^^^^^^^^^^^^^^^^^^^^^^^^^
+---------------------+------------------+---------------------------------------------------------+
| Key | Type | Description |
+=====================+==================+=========================================================+
| workflow | Workflow Model | The workflow that the transition currently happening |
+---------------------+------------------+---------------------------------------------------------+
| workflow_object | | Your Workflow | | The workflow object of the model that has the state |
| | | Object | | field in it |
+---------------------+------------------+---------------------------------------------------------+




Example Function
^^^^^^^^^^^^^^^^

.. code:: python
from river.models.hook import BEFORE, AFTER
def handle_transition(hook):
workflow = hook['payload']['workflow']
workflow_object = hook['payload']['workflow_object']
source_state = hook['payload']['transition_approval'].meta.source_state
destination_state = hook['payload']['transition_approval'].meta.destination_state
last_approved_by = hook['payload']['transition_approval'].transactioner
if hook['when'] == BEFORE:
print('A transition from %s to %s will soon happen on the object with id:%s and field_name:%s!' % (source_state.label, destination_state.label, workflow_object.pk, workflow.field_name))
elif hook['when'] == AFTER:
print('A transition from %s to %s has just happened on the object with id:%s and field_name:%s!' % (source_state.label, destination_state.label, workflow_object.pk, workflow.field_name))
print('Who approved it lately is %s' % last_approved_by.username)
def handle_approval(hook):
workflow = hook['payload']['workflow']
workflow_object = hook['payload']['workflow_object']
approved_by = hook['payload']['transition_approval'].transactioner
if hook['when'] == BEFORE:
print('An approval will soon happen by %s on the object with id:%s and field_name:%s!' % ( approved_by.username, workflow_object.pk, workflow.field_name ))
elif hook['when'] == AFTER:
print('An approval has just happened by %s on the object with id:%s and field_name:%s!' % ( approved_by.username, workflow_object.pk, workflow.field_name ))
def handle_complete(hook):
workflow = hook['payload']['workflow']
workflow_object = hook['payload']['workflow_object']
if hook['when'] == BEFORE:
print('The workflow will soon be complete for the object with id:%s and field_name:%s!' % ( workflow_object.pk, workflow.field_name ))
elif hook['when'] == AFTER:
print('The workflow has just been complete for the object with id:%s and field_name:%s!' % ( workflow_object.pk, workflow.field_name ))
def handle(context):
hook = context['hook']
if hook['type'] == 'on-transit':
handle_transition(hook)
elif hook['type'] == 'on-approved':
handle_approval(hook)
elif hook['type'] == 'on-complete':
handle_complete(hook)
else:
print("Unknown event type %s" % hook['type'])
26 changes: 26 additions & 0 deletions docs/hooking/hooking.rst
@@ -0,0 +1,26 @@
.. _hooking_guide:

Hook it Up
==========

The hookings in ``django-river`` can be created both specifically for a workflow object or for a whole workflow. ``django-river`` comes with some model objects and admin interfaces which you can use
to create the hooks.

* To create one for whole workflow regardless of what the workflow object is, go to
* ``/admin/river/onapprovedhook/`` to hook up to an approval
* ``/admin/river/ontransithook/`` to hook up to a transition
* ``/admin/river/oncompletehook/`` to hook up to the completion of the workflow

* To create one for a specific workflow object you should use the admin interface for the workflow object itself. One amazing feature of ``django-river`` is now that it creates a default admin interface
with the hookings for your workflow model class. If you have already defined one, ``django-river`` enriches your already defined admin with the hooking section. It is default enabled. To disable it
just define ``RIVER_INJECT_MODEL_ADMIN`` to be ``False`` in the ``settings.py``.


**Note: ** They can programmatically be created as well since they are model objects. If it is needed to be at workflow level, just don't provide the workflow object column. If it is needed
to be for a specific workflow object then provide it.
Here are the list of hook model object

* OnApprovedHook
* OnTransitHook
* OnCompleteHook

0 comments on commit d2b8173

Please sign in to comment.