Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add dev documentation for workflow operations
  • Loading branch information
cwilby authored Jun 20, 2021
commit 3367c422955bb004db582d09013c23058be9ecfb
150 changes: 148 additions & 2 deletions developer_manual/digging_deeper/flow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,154 @@
Nextcloud Flow
==============

Nextcloud Flow is the workflow engine of Nextcloud. It offers flexible, user-defined event-based task automation. Apps can register events or triggers which can start a flow, as well as actions which get executed once a trigger is hit and the constraints are satisfied.
Nextcloud Flow is a flexible, user-defined event-based workflow engine.

The workflow engine broadcasts events when certain trigger conditions are met.

Applications register event listeners with the workflow engine to receive events broadcast by the workflow engine when one or more trigger conditions are met.

Event listeners then register operations to handle those events.

An example flow might be converting Word documents into PDF when they are added to one folder, then move that Word document to another folder once it's finished.

The following sections define the individual components your application will need to integrate with the workflow engine.

At 36c3 blizzz gave a talk explaining Flow and `how to write actions and triggers. <https://mirror.eu.oneandone.net/projects/media.ccc.de/congress/2019/h264-sd/36c3-oio-174-eng-Building_Nextcloud_Flow_sd.mp4>`_ You can `find the slides of their talk here. <https://nextcloud.com/wp-content/themes/next/assets/files/Building_nextcloud_flow.pdf>`_

Contributions to this documentation are, as always, very welcome!
An example workflow can be found at https://github.com/nextcloud/workflow_pdf_converter.

Events
======

First, you should consider the events you want users to configure in your flow. Nextcloud currently dispatches the following events to the workflow engine:

Calendar
--------

- ``\OCA\DAV\CalDAV\CalDavBackend::createCalendar``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\OCA* is an app namespace. It's not public api and therefore shouldn't be documented/recommended as such

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to disagree. Since the workflow engine exposes these events (if it really does, no idea if that's correct), then the assumption is that apps may want to be able to handle those events in an operation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If WFE exposes the events for other apps they should be in OCP

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And what about third party apps, like Bookmarks? They expose events via WFE as well, should they all be in OCP?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say so

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would disagree, but it's not my decision :D 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looping in other lead developers @juliushaertl @nickvergessen. wdyt?^

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General remark:

If WFE exposes the events for other apps they should be in OCP

WFE might be a different thing here, as it's shipped.
But I'm definetly not going to send 80+ Events we have in Talk as OCP to the server. That's way to slow development cycle and I'm not going to add a temporary internal one until a public OCP one was merged.
So no, from my POV all events that are documented intentionally by the Devs are okay to be considered public API. For Talk that is: https://nextcloud-talk.readthedocs.io/en/latest/events/


Regarding the case here:

Nextcloud currently dispatches the following events to the workflow engine:

I'm not sure where this though it coming from. I'm not aware where this list would origin from. There are public events available to register entities, operations and checks: https://github.com/nextcloud/server/blob/aa039c986a3e8aaa97569d65ff1afd47a9b94a53/apps/workflowengine/lib/Manager.php#L685-L710

But I'm not aware dav would register calendars, subscriptions, etc. for those. Neither shares nor users.
The only known entity is files with those events:
https://github.com/nextcloud/server/blob/7d7ef1d2e68310cc8e0988a926406cddd241c257/apps/workflowengine/lib/Entity/File.php#L111-L117

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also agree that apps should still be able to use their own Events when considering them as public APIs.

Regarding the list I can only imagine that they are examples since the workflow engine would add listeners dynamically depending on the events that are configured, but by this depends on the actual Entity classes that are registered from apps https://github.com/nextcloud/server/blob/efb7448cd271f7f0cd21fd284fd1d3f9d729f20f/apps/workflowengine/lib/AppInfo/Application.php#L73-L78

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, for things like Calendar (or anything shipped) we should have those rather in OCP.

- ``\OCA\DAV\CalDAV\CalDavBackend::updateCalendar``
- ``\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar``
- ``\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::createCachedCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::updateCachedCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::deleteCachedCalendarObject``
- ``\OCA\DAV\CalDAV\CalDavBackend::createSubscription``
- ``\OCA\DAV\CalDAV\CalDavBackend::updateSubscription``
- ``\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription``
- ``\OCA\DAV\CalDAV\CalDavBackend::updateShares``
- ``\OCA\DAV\CalDAV\CalDavBackend::publishCalendar``

Contacts
--------

- ``\OCA\DAV\CardDAV\CardDavBackend::createCard``
- ``\OCA\DAV\CardDAV\CardDavBackend::updateCard``
- ``\OCA\DAV\CardDAV\CardDavBackend::deleteCard``

Files
-----

- ``\OCP\Files::preWrite``
- ``\OCP\Files::postWrite``
- ``\OCP\Files::preCreate``
- ``\OCP\Files::postCreate``
- ``\OCP\Files::preDelete``
- ``\OCP\Files::postDelete``
- ``\OCP\Files::preTouch``
- ``\OCP\Files::postTouch``
- ``\OCP\Files::preRename``
- ``\OCP\Files::postRename``
- ``\OCP\Files::preCopy``
- ``\OCP\Files::postCopy``
- ``\OCP\Files::read``

Shares
------

- ``\OCP\Share::preShare``
- ``\OCP\Share::postShare``
- ``\OCP\Share::postAcceptShare``
- ``\OCP\Share::preUnshare``
- ``\OCP\Share::postUnshare``
- ``\OCP\Share::postUnshareFromSelf``

Users
-----

- ``\OCP\IUser::preDelete``
- ``\OCP\IUser::postDelete``
- ``\OCP\IUser::preSetPassword``
- ``\OCP\IUser::postSetPassword``
- ``\OCP\IUser::changeUser``
- ``\OCP\IUser::preDelete``

Listeners
=========

Event listeners are classes that are registered with the manager along with an array of events that it should listen for.

The first event listener your application should listen for is the ``RegisterOperationsEvent`` event.

This event is dispatched when the workflow engine goes to resolve registered event listeners that should receive an event it is broadcasting.

This initial event listener should register your Operations, and register the name of the JS bundle containing a Vue component that can be used to configure conditions for your event listeners to proceed.

`An example RegisterOperationsEvent listener can be found here <https://github.com/nextcloud/workflow_pdf_converter/blob/master/lib/Listener/RegisterFlowOperationsListener.php>`_

This event listener should be registered within the ``register`` function of your ``Application`` class. ::

public function register(IRegistrationContext $context): void {
$context->registerEventListener(
RegisterOperationsEvent::class,
RegisterFlowOperationsListener::class
);
}

Operations
==========

Operations are classes that are registered with one or more event listeners.

When one or more event listeners receive an event, they can all be configured to call a single operation if it minimizes duplicated code. (Use your best judgement.)

This class must implement one of the following `IOperation <https://github.com/nextcloud/server/blob/master/lib/public/WorkflowEngine/IOperation.php#L33>`_ interfaces:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't have to. Talk is implementing IOperation directly. Works as well. Only when you want to have the other things you need to implement those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the line looks unrelated here?


- `ISpecificOperation <https://github.com/nextcloud/server/blob/master/lib/public/WorkflowEngine/ISpecificOperation.php>`_ - an interface that represents an operation designed to work with one entity type.

- `IComplexOperation <https://github.com/nextcloud/server/blob/master/lib/public/WorkflowEngine/IComplexOperation.php>`_ - an interface that represents an operation that performs it's own trigger logic.

When an event is fired that your operation is listening for, it will call the onEvent function of your operation.

`An example ConvertPDFOperation operation can be found here <https://github.com/nextcloud/workflow_pdf_converter/tree/master/lib/Operation.php>`_

The operation should be registered against the event in the ``handle`` function of your ``RegisterOperationsEvent`` listener.

Configuration Component
=======================

The configuration component is what your user sees when they add your flow and go to configure it's rules.

The ``RegisterOperationsEvent`` listener we created earlier registered the name of the JS bundle.

This JS bundle should be compiled using ``@nextcloud/webpack-vue-config`` through the following steps:

First, create a `webpack.js` file in the root of your application's folder. ::

const webpackConfig = require('@nextcloud/webpack-vue-config')

module.exports = webpackConfig

Then, create ``src/main.js`` with the following contents ::

import ConvertToPdf from './ConvertToPdf'

OCA.WorkflowEngine.registerOperator({
id: 'OCA\\WorkflowPDFConverter\\Operation',
operation: 'keep;preserve',
options: ConvertToPdf,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is "legacy". going forward element should be used and allows apps to provide their content isolated, so it does not cause conflicts when the app and server use different Vue versions, etc. See the following PR and from there linked PRs and issues:
nextcloud/spreed#14367

color: '#dc5047'
})

The ``OCA.WorkflowEngine.registerOperator`` function tells Nextcloud about your operation, along with the color, and the component that contains configuration specific to your flow.