diff --git a/admin_manual/contents.rst b/admin_manual/contents.rst index b0277c542..636edc777 100644 --- a/admin_manual/contents.rst +++ b/admin_manual/contents.rst @@ -12,6 +12,7 @@ Table of contents configuration_server/index occ_command apps_management + exapps_management/index configuration_user/index configuration_files/index file_workflows/index diff --git a/admin_manual/exapps_management/Concepts.rst b/admin_manual/exapps_management/Concepts.rst new file mode 100644 index 000000000..c944cc69d --- /dev/null +++ b/admin_manual/exapps_management/Concepts.rst @@ -0,0 +1,19 @@ +Concepts +======== + +API Access Control Mechanism +---------------------------- + +Each application defines list of API groups it intends to access. + +This system easily allows you to increase the level of trust in applications. +Even prior to installation, it's possible to ascertain the API groups to which an application will gain access. + +Extensible Deployment +--------------------- + +The system should support the expansion and integration of new deployment methods, avoiding any tight coupling with a specific deployment type. +Applications should be capable of indicating the deployment methods they can accommodate. + +Given the evolving landscape of new technologies and the potential emergence of more intricate or simplified deployment options, +the system is architected to seamlessly embrace the integration of novel deployment modes. diff --git a/admin_manual/exapps_management/CreationOfDeployDaemon.rst b/admin_manual/exapps_management/CreationOfDeployDaemon.rst new file mode 100644 index 000000000..38bb89657 --- /dev/null +++ b/admin_manual/exapps_management/CreationOfDeployDaemon.rst @@ -0,0 +1,135 @@ + .. _create-deploy-daemon: + +Creation of Deploy Daemon +========================= + +The Deploy Daemon (DaemonConfig) is used to orchestrate the deployment of ExApps. + +.. note:: + + Currently only ``docker-install`` and ``manual-install`` deployment methods are supported. + +The recommended daemon configuration is using `AppAPI Docker Socket Proxy `_. + +.. image:: ./img/app_api_3.png + + +You can choose one of the basic configuration templates and adjust to your needs. + +.. note:: We highly recommend to use UI to create Deploy Daemons. + +Register Deploy daemon form +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. ``Name``: unique name of the Deploy daemon +2. ``Display name``: the name that will be displayed in the UI +3. ``Deployment method``: by default you will need to choose ``docker_install``, ``manual_install`` is for development or custom use case of manual ExApp installation +4. ``Daemon Host``: hostname/IP address + port of the Deploy daemon +5. ``Nextcloud URL``: autofilled with current domain, you might need to change the protocol to http/https depending on your setup +6. ``Set as default daemon``: check if you want set new Deploy daemon as default +7. ``Enable https``: check if your Deploy daemon (Docker Socket Proxy) is configured with TLS +8. Deploy Config: + 9. ``Network``: Docker network name, depends on your networking setup, enforces to "host" if "Enable https" is checked + 10. ``HaProxy password``: password for Docker Socket Proxy, if it is configured with TLS + 11. ``Compute Device``: CPU, CUDA or ROCm, depending on your hardware config on Deploy daemon host machine + 12. ``Add additional option`` (see :ref:`additional_options_list`): setup additional KEY + VALUE deploy config options + +.. note:: + + For remote DSP setup, it should expose the ports on the host. + + +.. _create-deploy-daemon-cli: + +OCC CLI +^^^^^^^ + +There are a few commands to manage Deploy Daemons: + +1. Register ``occ app_api:daemon:register`` +2. Unregister ``occ app_api:daemon:unregister`` +3. List registered daemons ``occ app_api:daemon:list`` + +Register +-------- + +Register Deploy Daemon (DaemonConfig). + +Command: ``app_api:daemon:register [--net NET] [--haproxy_password HAPROXY_PASSWORD] [--compute_device COMPUTE_DEVICE] [--set-default] [--] `` + +Arguments +********* + + * ``name`` - unique name of the daemon (e.g. ``docker_local_sock``) + * ``display-name`` - name of the daemon (e.g. ``My Local Docker``, will be displayed in the UI) + * ``accepts-deploy-id`` - type of deployment (``docker-install`` or ``manual-install``) + * ``host`` - **path to docker-socket** or the Docker Socket Proxy: ``address:port`` + * ``protocol`` - protocol used to communicate with the Daemon/ExApps (``http`` or ``https``) + * ``nextcloud_url`` - Nextcloud URL, Daemon config required option (e.g. ``https://nextcloud.local``) + +Options +******* + + * ``--net [network-name]`` - ``[required]`` network name to bind docker container to (default: ``host``) + * ``--haproxy_password HAPROXY_PASSWORD`` - ``[optional]`` password for AppAPI Docker Socket Proxy + * ``--compute_device GPU`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``cpu|cuda|rocm``, default: ``cpu``) + * ``--set-default`` - ``[optional]`` set created daemon as default for ExApps installation + +DeployConfig +************ + +DeployConfig is a set of additional options in Daemon config, which are used in deployment algorithms to configure +ExApp container. + +.. code-block:: json + + { + "net": "host", + "nextcloud_url": "https://nextcloud.local", + "haproxy_password": "some_secure_password", + "computeDevice": { + "id": "cuda", + "name": "CUDA (NVIDIA)", + }, + } + +DeployConfig options +******************** + + * ``net`` **[required]** - network name to bind docker container to (default: ``host``) + * ``nextcloud_url`` **[required]** - Nextcloud URL (e.g. ``https://nextcloud.local``) + * ``haproxy_password`` *[optional]* - password for AppAPI Docker Socket Proxy + * ``computeDevice`` *[optional]* - Compute device to attach to the daemon (e.g. ``{ "id": "cuda", "label": "CUDA (NVIDIA)" }``) + +Unregister +---------- + +Unregister Deploy Daemon (DaemonConfig). + +Command: ``app_api:daemon:unregister `` + +List registered daemons +----------------------- + +List registered Deploy Daemons (DaemonConfigs). + +Command: ``app_api:daemon:list`` + +Nextcloud AIO +^^^^^^^^^^^^^ + +In case of AppAPI installed in AIO, default Deploy Daemon is registered automatically. +It is possible to register additional Deploy Daemons with the same ways as described above. + + +.. _additional_options_list: + +Additional options +^^^^^^^^^^^^^^^^^^ + +There is a possibility to add additional options to the Deploy Daemon configuration, +which are key-value pairs. + +Currently, the following options are available: + + - ``OVERRIDE_APP_HOST`` - can be used to override the host that will be used for ExApp binding (not passed to ExApp container envs) diff --git a/admin_manual/exapps_management/DeployConfigurations.rst b/admin_manual/exapps_management/DeployConfigurations.rst new file mode 100644 index 000000000..32a71952b --- /dev/null +++ b/admin_manual/exapps_management/DeployConfigurations.rst @@ -0,0 +1,384 @@ +.. _deploy-configs: + +Deployment configurations +========================= + +Currently, only one kind of application deployment is supported: + * **Docker Deploy Daemon** + +Docker Deploy Daemon +-------------------- + +Orchestrates the deployment of applications as Docker containers. + +.. warning:: + + The administrator is responsible for the security actions taken to configure the Docker daemon connected to the Nextcloud instance. + + These schemes are only examples of possible configurations. + + We recommend that you use the `AppAPI Docker Socket Proxy `_ or `AIO Docker Socket Proxy <#nextcloud-in-docker-aio-all-in-one>`_ container. + +There are several Docker Daemon Deploy configurations (example schemes): + + * Nextcloud and Docker on the **same host** (via socket or DockerSocketProxy) + * Nextcloud on the host and Docker on a **remote** host (via DockerSocketProxy with HTTPS) + * Nextcloud and **ExApps** in the **same Docker** (via DockerSocketProxy) + * Nextcloud in AIO Docker and **ExApps** in the **same Docker** (via AIO DockerSocketProxy) + + +NC & Docker on the Same-Host +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The simplest configuration is when Nextcloud is installed on the host and Docker is on the same host and applications are deployed to it. + +.. mermaid:: + + stateDiagram-v2 + classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain + classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px + + Host + + state Host { + Nextcloud --> Daemon : /var/run/docker.sock + Daemon --> Containers + + state Containers { + ExApp1 + -- + ExApp2 + -- + ExApp3 + } + } + + class Nextcloud nextcloud + class Daemon docker + class ExApp1 python + class ExApp2 python + class ExApp3 python + +Suggested config values(template *Custom default*): + 1. Daemon host: ``/var/run/docker.sock`` + 2. HTTPS checkbox: *not supported using docker socket* + 3. Network: ``host`` + 4. HaProxy password: **not supported using raw docker socket, should be empty** + +--- + +Suggested way to communicate with Docker via `Docker Socket Proxy container `_. + +.. mermaid:: + + stateDiagram-v2 + classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain + classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px + + Host + + state Host { + Nextcloud --> DockerSocketProxy: by port + Docker --> Containers + Docker --> DockerSocketProxy : /var/run/docker.sock + + state Containers { + DockerSocketProxy --> ExApp1 + DockerSocketProxy --> ExApp2 + DockerSocketProxy --> ExApp3 + } + } + + class Nextcloud nextcloud + class Docker docker + class ExApp1 python + class ExApp2 python + class ExApp3 python + +Suggested config values(template *Docker Socket Proxy*): + 1. Daemon host: ``localhost:2375`` + Choose **A** or **B** option: + A. Docker Socket Proxy should be deployed with ``network=host`` and ``BIND_ADDRESS=127.0.0.1`` + B. Docker Socket Proxy should be deployed with ``network=bridge`` and it's port should be published to host's 127.0.0.1(e.g. **-p 127.0.0.1:2375:2375**) + 2. HTTPS checkbox: **disabled** + 3. Network: ``host`` + 4. HaProxy password: **should not be empty** + +.. warning:: + + Be careful with option ``A``, by default **Docker Socket Proxy** binds to ``*`` if ``BIND_ADDRESS`` is not specified during container creation. + Check opened ports after finishing configuration. + + +Docker on a remote host +^^^^^^^^^^^^^^^^^^^^^^^ + +Distributed configuration occurs when Nextcloud is installed on one host and Docker is located on a remote host, resulting in the deployment of applications on the remote host. + +Benefit: no performance impact on Nextcloud host. + +In this case, the AppAPI uses a Docker Socket Proxy deployed on remote host to access docker socket and ExApps. + +.. mermaid:: + + stateDiagram-v2 + classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain + classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px + + Direction LR + + Host1 --> Host2 : by port + + state Host1 { + Nextcloud + } + + state Host2 { + [*] --> DockerSocketProxy : by port + Daemon --> Containers + + state Containers { + [*] --> DockerSocketProxy : /var/run/docker.sock + DockerSocketProxy --> ExApp1 + DockerSocketProxy --> ExApp2 + DockerSocketProxy --> ExApp3 + } + } + + class Nextcloud nextcloud + class Daemon docker + class ExApp1 python + class ExApp2 python + class ExApp3 python + +Suggested config values(template *Docker Socket Proxy*): + 1. Daemon host: ADDRESS_OF_REMOTE_MACHINE (e.g. **server_name.com:2375**) + 2. HTTPS checkbox: ``enabled`` + 3. Network: ``host`` + 4. HaProxy password: **should not be empty** + +NC & ExApps in the same Docker +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Applications are deployed in the same docker where Nextcloud resides. + +Suggested way to communicate with Docker: via ``docker-socket-proxy``. + +.. mermaid:: + + stateDiagram-v2 + classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain + classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px + + Host + + state Host { + Daemon --> Containers + + state Containers { + [*] --> DockerSocketProxy : /var/run/docker.sock + Nextcloud --> DockerSocketProxy: by port + -- + DockerSocketProxy --> ExApp1 + DockerSocketProxy --> ExApp2 + } + } + + class Nextcloud nextcloud + class Daemon docker + class ExApp1 python + class ExApp2 python + class ExApp3 python + +Suggested config values(template *Docker Socket Proxy*): + 1. Daemon host: nextcloud-appapi-dsp:2375 + 2. HTTPS checkbox: ``disabled`` + 3. Network: `user defined network `_ + 4. HaProxy password: **should not be empty** + +.. note:: + Network **should not be the default docker's bridge** as it does not support DNS resolving by container names. + + This means that **Docker Socket Proxy**, **Nextcloud** and **ExApps** containers should all be in the same docker network, different from the default **bridge**. + + +.. _nextcloud-in-docker-aio-all-in-one: + +Nextcloud in Docker AIO (all-in-one) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In case of AppAPI is in Docker AIO setup (installed in Nextcloud container). + +.. note:: + + AIO Docker Socket Proxy container must be enabled. + +.. mermaid:: + + stateDiagram-v2 + classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef docker2 fill: #1f97ee, color: transparent, font-size: 20px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain + classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain + classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px + + Host + + state Host { + Daemon --> Containers + + state Containers { + [*] --> NextcloudAIOMasterContainer : /var/run/docker.sock + [*] --> DockerSocketProxy : /var/run/docker.sock + NextcloudAIOMasterContainer --> Nextcloud + AppAPI --> Nextcloud : installed in + Nextcloud --> DockerSocketProxy + DockerSocketProxy --> ExApp1 + DockerSocketProxy --> ExApp2 + DockerSocketProxy --> ExApp3 + } + } + + class Nextcloud nextcloud + class Daemon docker + class Daemon2 docker2 + class ExApp1 python + class ExApp2 python + class ExApp3 python + +AppAPI will automatically create default default DaemonConfig to use AIO Docker Socket Proxy as orchestrator to create ExApp containers. + +.. note:: + + Default DaemonConfig will be created only if the default DaemonConfig is not already registered. + + +Default AIO Deploy Daemon +************************* + +Nextcloud AIO has a specifically created Docker Socket Proxy container to be used as the Deploy Daemon in AppAPI. +It has `fixed parameters `_: + +* Name: ``docker_aio`` +* Display name: ``AIO Docker Socket Proxy`` +* Accepts Deploy ID: ``docker-install`` +* Protocol: ``http`` +* Host: ``nextcloud-aio-docker-socket-proxy:2375`` +* Compute device: ``CPU`` +* Network: ``nextcloud-aio`` +* Nextcloud URL (passed to ExApps): ``https://$NC_DOMAIN`` + +Docker Socket Proxy security +**************************** + +AIO Docker Socket Proxy has strictly limited access to the Docker APIs described in `HAProxy configuration `_. + + +NC to ExApp Communication +------------------------- + +Each type of DeployDaemon necessarily implements the ``resolveExAppUrl`` function. + +It has such prototype: + +.. code-block:: php + + public function resolveExAppUrl( + string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth + ) {} + +where: + +* **protocol** is daemon protocol value +* **host** is daemon host value, *can be DNS:port or IP:PORT or even path to docker socket*. +* **port** is an integer with ExApp port +* **deployConfig** can be custom for each Daemon type +* **auth** is an optional array, with *Basic Authentication* data if needed to access ExApp + +.. note:: + + Starting with AppAPI version ``2.5.0``, the optional additional parameter *OVERRIDE_APP_HOST* can be used to + override the host that will be used for ExApp binding. + + It can be ``0.0.0.0`` in some specific configurations, when VPN is used + or both Nextcloud instance and ExApps are one the same physical machine but different virtual environments. + + Also you can specify something like ``10.10.2.5`` and in this case ``ExApp`` wil try to bind to that address and + AppAPI will try to send request s directly to this address assuming that ExApp itself bound on it. + +The simplest implementation is in **Manual-Install** deploy type: + +.. code-block:: php + + public function resolveExAppUrl( + string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth + ): string { + $auth = []; + if (isset($deployConfig['additional_options']['OVERRIDE_APP_HOST']) && + $deployConfig['additional_options']['OVERRIDE_APP_HOST'] !== '' + ) { + $wideNetworkAddresses = ['0.0.0.0', '127.0.0.1', '::', '::1']; + if (!in_array($deployConfig['additional_options']['OVERRIDE_APP_HOST'], $wideNetworkAddresses)) { + $host = $deployConfig['additional_options']['OVERRIDE_APP_HOST']; + } + } + return sprintf('%s://%s:%s', $protocol, $host, $port); + } + +Here we see that AppAPI send requests to **host**:**port** specified during daemon creation. + +Now let's take a look at the Docker Daemon implementation of ``resolveExAppUrl``: + +.. code-block:: php + + public function resolveExAppUrl( + string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth + ): string { + $auth = []; + if (isset($deployConfig['additional_options']['OVERRIDE_APP_HOST']) && + $deployConfig['additional_options']['OVERRIDE_APP_HOST'] !== '' + ) { + $wideNetworkAddresses = ['0.0.0.0', '127.0.0.1', '::', '::1']; + if (!in_array($deployConfig['additional_options']['OVERRIDE_APP_HOST'], $wideNetworkAddresses)) { + return sprintf( + '%s://%s:%s', $protocol, $deployConfig['additional_options']['OVERRIDE_APP_HOST'], $port + ); + } + } + $host = explode(':', $host)[0]; + if ($protocol == 'https') { + $exAppHost = $host; + } elseif (isset($deployConfig['net']) && $deployConfig['net'] === 'host') { + $exAppHost = 'localhost'; + } else { + $exAppHost = $appId; + } + if (isset($deployConfig['haproxy_password']) && $deployConfig['haproxy_password'] !== '') { + $auth = [self::APP_API_HAPROXY_USER, $deployConfig['haproxy_password']]; + } + return sprintf('%s://%s:%s', $protocol, $exAppHost, $port); + } + +Here we have much more complex algorithm of detecting to where requests should be send. + +First of all if protocol is set to ``https`` AppAPI always send requests to daemon host, +and this is in case of ``https`` it is a HaProxy that will forward requests to ExApps that will be listen on ``localhost`` + +Briefly it will look like this(*haproxy_host==daemon host value*): + +NC --> *https* --> ``haproxy_host:ex_app_port`` --> *http* --> ``localhost:ex_app_port`` + +When protocol is not ``https`` but ``http``, then what will be the endpoint where to send requests is determined by ``$deployConfig['net']`` value. + +If ``net`` is defined and equal to ``host`` then AppAPI assumes that ExApp is installed somewhere in the current host network and will be available on ``localhost`` loop-back adapter. + +NC --> *http* --> ``localhost:ex_app_port`` + +In all other cases ExApp should be available by it's name: e.g. when using docker **custom bridge** network all containers available by DNS. + +NC --> *http* --> ``app_container_name:ex_app_port`` + +This three different types of communication covers all most popular configurations. diff --git a/admin_manual/exapps_management/Installation.rst b/admin_manual/exapps_management/Installation.rst new file mode 100644 index 000000000..389c58f65 --- /dev/null +++ b/admin_manual/exapps_management/Installation.rst @@ -0,0 +1,85 @@ +Installation +============ + +There are two ways to install the AppAPI: from the `AppStore `_ or from the source code. + +.. note:: + + AppAPI 3.0.0 is the last version supported Nextcloud 27. + + +Installation from the AppStore +------------------------------ + +Simply navigate to the Apps management page in your Nextcloud and setup the AppAPI from the Tools category. + +Installation from the source code +--------------------------------- + +To install the AppAPI from the source code, follow these steps: + +1. Clone the AppAPI repository into your apps directory +******************************************************* + +Clone the latest main branch: + + .. code-block:: bash + + git clone https://github.com/cloud-py-api/app_api.git + +or clone a specific version by specifying the version tag: + + .. code-block:: bash + + git clone https://github.com/cloud-py-api/app_api.git --branch + +where ```` is the version you want to install. + + +2. Build frontend assets in production mode +******************************************** + + .. code-block:: bash + + npm ci && npm run build + +3. Enable the AppAPI +******************** + + .. code-block:: bash + + ./occ app:enable --force app_api + + +To install it in development mode, follow the instructions on this page: :ref:`dev-setup`. + +4. Setup Deploy daemon +********************** + +Upon the successful installation of the AppAPI, a one-time configuration is essential. +Details on this configuration can be found in the subsequent section: :ref:`create-deploy-daemon`. + +4.1 Deploy daemon configuration +******************************* + +Deploy daemon configuration steps: + +1. Go to the AppAPI admin settings. +2. Click on the "Register Daemon" button. +3. Fill in the required fields: + - ``Name``: unique name of the Deploy daemon + - ``Display name``: the name that will be displayed in the UI + - ``Deployment method``: by default you will need to choose ``docker_install``, ``manual_install`` is for development or custom use case of manual ExApp installation + - ``Daemon Host``: hostname/IP address + port of the Deploy daemon + - ``Nextcloud URL``: autofilled with current domain, you might need to change the protocol to http/https depending on your setup + - ``Set as default daemon``: check if you want set new Deploy daemon as default + - ``Enable https``: check if your Deploy daemon (Docker Socket Proxy) is configured with TLS + - Deploy Config: + - ``Network``: Docker network name, depends on your networking setup, enforces to "host" if "Enable https" is checked + - ``HaProxy password``: password for Docker Socket Proxy, if it is configured with TLS + - ``Compute Device``: CPU, CUDA or ROCm, depending on your hardware config on Deploy daemon host machine + - ``Add additional option`` (see :ref:`additional_options_list`): setup additional KEY + VALUE deploy config options +4. Check connection: to verify configuration is correct +5. Register: to save the Deploy daemon configuration + +Deployment configuration examples can be found :ref:`here `. diff --git a/admin_manual/exapps_management/ManagingExternalApplications.rst b/admin_manual/exapps_management/ManagingExternalApplications.rst new file mode 100644 index 000000000..3f11f524b --- /dev/null +++ b/admin_manual/exapps_management/ManagingExternalApplications.rst @@ -0,0 +1,117 @@ +Managing External Applications +============================== + +There are two ways to manage ExApps: + +1. Using OCC CLI tool +2. Using the ExApp Management UI + + +OCC CLI +^^^^^^^ + +There are several commands to work with ExApps: + +1. Register +2. Unregister +3. Update +4. Enable +5. Disable +6. List ExApps +7. List ExApp users (removed since AppAPI 3.0.0) +8. List ExApp scopes + +Register +-------- + +Command: ``app_api:app:register [--force-scopes] [--info-xml INFO-XML] [--json-info JSON-INFO] [--] `` + +The register command is the first ExApp installation step. + +Arguments +********* + + * ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container) + * ``daemon-config-name`` - unique name of the daemon (e.g. ``docker_local_sock``) + +Options +******* + + * ``--force-scopes`` *[optional]* - force scopes approval + * ``--json-info JSON-INFO`` **[optional]** - ExApp deploy JSON info (json string) + * ``--info-xml INFO-XML`` **[optional]** - path to info.xml file (url or local absolute path) + + +Unregister +---------- + +Command: ``app_api:app:unregister [--rm-data] [--force] [--silent] [--] `` + +To remove an ExApp you can use the unregister command. +There are additional options to keep the ExApp persistent storage (data volume). + +Arguments +********* + + * ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container) + +Options +******* + + * ``--rm-data`` *[optional]* - remove ExApp persistent storage (data volume) + * ``--force`` *[optional]* - continue removal even if some error occurs. + * ``--silent`` *[optional]* - print a minimum of information, display only some errors, if any. + +Update +------ + +Command: ``app_api:app:update [--info-xml INFO-XML] [--force-update] [--force-scopes] [-e|--enabled] [--] `` + +ExApp will be updated if there is a new version available. + +Arguments +********* + + * ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container) + +Options +******* + + * ``--info-xml INFO-XML`` **[optional]** - path to info.xml file (url or local absolute path) + * ``--force-update`` *[optional]* - force ExApp update (do not prompt for confirmation) + * ``--force-scopes`` *[optional]* - force scopes approval (accept all scopes) + * ``-e|--enabled`` *[optional]* - enable ExApp after update + +Enable +------ + +Command: ``app_api:app:enable `` + +Disable +------- + +Command: ``app_api:app:disable `` + +List ExApps +----------- + +Command: ``app_api:app:list`` + +ListExApps command will show all ExApps: + +.. code-block:: + + ExApps: + appid (Display Name): version [enabled/disabled] + to_gif_example (To Gif Example): 1.0.0 [enabled] + upscaler_example (Upscaler Example): 1.0.0 [enabled] + +Using the ExApp Management UI +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ExApps management is similar to default Apps management. +To access ExApps management navigate using Admin settings dropdown menu or from AppAPI admin settings section. + +.. note:: + + ExApps management support only apps from App Store. For manual-install type use CLI ExApps management commands. diff --git a/admin_manual/exapps_management/TestDeploy.rst b/admin_manual/exapps_management/TestDeploy.rst new file mode 100644 index 000000000..8cdb11175 --- /dev/null +++ b/admin_manual/exapps_management/TestDeploy.rst @@ -0,0 +1,97 @@ +.. _test_deploy: + +Test Deploy Daemon +------------------ + +You can test each Daemon configuration deployment from the AppAPI Admin settings. + +.. image:: ./img/test_deploy.png + + +Status Checks +^^^^^^^^^^^^^ + +The Deploy test installs a `test-deploy `_ ExApp +to verify each step of the deployment process, including a hardware support check - +for each compute device, there is a separate Docker image. + +.. note:: + The Test Deploy ExApp container is not removed after the test as it's needed for logs and status checks. + You can remove it after testing from the External Apps page. + The Docker images are also not removed from the Daemon; you can clean up unused images with the ``docker image prune`` command. + +.. image:: ./img/test_deploy_modal_4.png + + +Register +******** + +The Register step is the first step; it checks if the ExApp is registered in Nextcloud. + +Image Pull +********** + +The Image Pull step downloads the ExApp Docker image. + +Possible errors: + +- Image not found (e.g. not public, no image found for your hardware architecture) +- Image pull failed (e.g., due to network issues) +- Image pull timeout +- Your Docker Socket Proxy is not configured correctly and blocks access to this Docker Engine API + +Container Started +***************** + +The Container Started step verifies that the ExApp container is created and started successfully. + +Possible errors: + +- Container failed to start with GPU support (may be missing or misconfigured) + - For NVIDIA, refer to the `NVIDIA Docker configuration docs `_. + - For AMD, refer to the `ROCm Docker configuration docs `_. +- The ExApp issue during startup (e.g. not enough memory) + + +Heartbeat +********* + +The Heartbeat step checks if the container's health check is finished and the container is healthy. +The ExApp might have additional pre-configuration logic during this step. + +Possible errors: + +- ExApp failed to start a web server, e.g., if the port is already in use (this should be visible in the container logs) +- ExApp heartbeat_count keeps increasing, this may indicate that the ExApp couldn't start properly +- Nextcloud can not reach the ExApp container, e.g., due to a network issue or a firewall + +Init +**** + +The Init step checks if the ExApp is initialized and ready to use. +During the init step, the ExApp may perform downloads of extra stuff required for it. + +Possible errors: + +- Initialization failed (e.g., due to network issues or timeout) + + +Enabled +******* + +The Enabled step checks if the ExApp is enabled and ready to use. +During this step, the ExApp registers all the required and available APIs of the Nextcloud AppFramework. + +Possible errors: + +- ExApp did not respond to the enable request +- ExApp failed to enable due to a failure in registering AppAPI Nextcloud AppFramework APIs (this should be visible both in the container logs and in the Nextcloud logs if there are any errors) + + +Download Logs +^^^^^^^^^^^^^ + +You can download the logs of the last test deploy attempt container. + +.. note:: + Downloading Docker container logs is only possible for containers using the json-file or journald logging drivers. diff --git a/admin_manual/exapps_management/img/app_api_1.png b/admin_manual/exapps_management/img/app_api_1.png new file mode 100755 index 000000000..db88faec9 Binary files /dev/null and b/admin_manual/exapps_management/img/app_api_1.png differ diff --git a/admin_manual/exapps_management/img/app_api_2.png b/admin_manual/exapps_management/img/app_api_2.png new file mode 100644 index 000000000..70ada7ec6 Binary files /dev/null and b/admin_manual/exapps_management/img/app_api_2.png differ diff --git a/admin_manual/exapps_management/img/app_api_3.png b/admin_manual/exapps_management/img/app_api_3.png new file mode 100644 index 000000000..aa01934d3 Binary files /dev/null and b/admin_manual/exapps_management/img/app_api_3.png differ diff --git a/admin_manual/exapps_management/img/app_api_4.png b/admin_manual/exapps_management/img/app_api_4.png new file mode 100644 index 000000000..839058809 Binary files /dev/null and b/admin_manual/exapps_management/img/app_api_4.png differ diff --git a/admin_manual/exapps_management/img/docker.png b/admin_manual/exapps_management/img/docker.png new file mode 100755 index 000000000..6d436d380 Binary files /dev/null and b/admin_manual/exapps_management/img/docker.png differ diff --git a/admin_manual/exapps_management/img/nextcloud.svg b/admin_manual/exapps_management/img/nextcloud.svg new file mode 100644 index 000000000..5375040d6 --- /dev/null +++ b/admin_manual/exapps_management/img/nextcloud.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/admin_manual/exapps_management/img/test_deploy.png b/admin_manual/exapps_management/img/test_deploy.png new file mode 100644 index 000000000..2ca76c1cb Binary files /dev/null and b/admin_manual/exapps_management/img/test_deploy.png differ diff --git a/admin_manual/exapps_management/img/test_deploy_modal_2.png b/admin_manual/exapps_management/img/test_deploy_modal_2.png new file mode 100644 index 000000000..1c3b0c0dd Binary files /dev/null and b/admin_manual/exapps_management/img/test_deploy_modal_2.png differ diff --git a/admin_manual/exapps_management/img/test_deploy_modal_4.png b/admin_manual/exapps_management/img/test_deploy_modal_4.png new file mode 100644 index 000000000..42fd3b918 Binary files /dev/null and b/admin_manual/exapps_management/img/test_deploy_modal_4.png differ diff --git a/admin_manual/exapps_management/index.rst b/admin_manual/exapps_management/index.rst new file mode 100644 index 000000000..35bf4d7f6 --- /dev/null +++ b/admin_manual/exapps_management/index.rst @@ -0,0 +1,13 @@ +================= +ExApps management +================= + +.. toctree:: + :maxdepth: 2 + + Installation + DeployConfigurations + CreationOfDeployDaemon + TestDeploy + ManagingExternalApplications + Concepts diff --git a/developer_manual/exapp_development/DevSetup.rst b/developer_manual/exapp_development/DevSetup.rst new file mode 100644 index 000000000..e147e896b --- /dev/null +++ b/developer_manual/exapp_development/DevSetup.rst @@ -0,0 +1,59 @@ +.. _dev-setup: + +Setting up dev environment +========================== + +We highly recommend using `Julius Haertl docker setup `_ for the Nextcloud dev setup. + +Suggested IDE: **PhpStorm**, though you can certainly use any IDE of your preference such as **VS Code** or **Vim**. + +Get last version from GitHub +"""""""""""""""""""""""""""" + +Assuming you're in the ``apps`` folder of Nextcloud with command :command:`git`:: + + git clone https://github.com/cloud-py-api/app_api.git + +Change to the ``app_api`` directory with :command:`shell`:: + + cd app_api + +Then, build frontend assets in development mode with :command:`shell`:: + + npm ci && npm run dev + +After this, you can enable it from the directory where the ``occ`` command resides, with :command:`shell`:: + + ./occ app:enable --force app_api + +In Place of a Conclusion +"""""""""""""""""""""""" + +There are several make commands available to ease frequent development actions. + +To see the complete list, execute ``make help``. + +Docker remote API +***************** + +The Docker Engine remote API can be easily configured via ``make dock2port`` command. +The command will create a docker container to provide remote Docker Engine API. + +Afterward, register DaemonConfigs in Nextcloud using ``make dock-port`` command. + +Docker by socket +**************** + +For Docker via socket, use the command ``make dock-sock``. +This registers DaemonConfigs in Nextcloud for the default socket connection (``/var/run/docker.sock``). + +Make sure that socket has enough permissions for Nextcloud and webserver user to access it +and actually forwarded to the container: + +.. code-block:: + + ... + volumes: + ... + - /var/run/docker.sock:/var/run/docker.sock + ... diff --git a/developer_manual/exapp_development/faq/BehindCompanyProxy.rst b/developer_manual/exapp_development/faq/BehindCompanyProxy.rst new file mode 100644 index 000000000..fe696e122 --- /dev/null +++ b/developer_manual/exapp_development/faq/BehindCompanyProxy.rst @@ -0,0 +1,161 @@ +Corporate Proxy - Permanent Settings for PHP CLI +================================================ + +If you're using our application within a corporate network that requires proxy settings, you might encounter issues when running PHP CLI commands that attempt to access the internet. + +To resolve this, you need to configure permanent proxy settings for the PHP CLI environment. + +Symptoms +-------- + +When running the command: + +.. code-block:: bash + + php occ app_api:app:register --force-scopes test-deploy docker_socket_proxy --info-xml https://raw.githubusercontent.com/cloud-py-api/test-deploy/main/appinfo/info.xml --test-deploy-mode --no-ansi --no-warnings + +You may receive an error similar to: + +.. code-block:: text + + file_get_contents(https://raw.githubusercontent.com/cloud-py-api/test-deploy/main/appinfo/info.xml): Failed to open stream: Connection timed out at /var/www/html/custom_apps/app_api/lib/Service/ExAppService.php#277 + +Cause +----- + +This issue occurs because the PHP CLI environment does not have the proxy settings configured, unlike the web PHP environment which may already be using proxy settings specified in your web server configuration. + +Permanent Solution +------------------ + +To permanently configure proxy settings for PHP CLI, you can either modify the PHP CLI `php.ini` file or set environment variables system-wide. + +Method 1: Edit PHP CLI `php.ini` File +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. **Locate the PHP CLI `php.ini` File** + + Run the following command to find the loaded configuration file for PHP CLI: + + .. code-block:: bash + + php --ini + + Look for the line: + + .. code-block:: text + + Loaded Configuration File: /path/to/php.ini + +2. **Edit the `php.ini` File** + + Open the `php.ini` file in a text editor with appropriate permissions: + + .. code-block:: bash + + sudo nano /path/to/php.ini + +3. **Add Proxy Settings** + + Add the following lines to configure the proxy settings: + + .. code-block:: ini + + [HTTP] + ; Proxy settings for HTTP + http.proxy_host = "proxy.example.com" + http.proxy_port = 8080 + http.proxy_user = "username" + http.proxy_password = "password" + + [HTTPS] + ; Proxy settings for HTTPS + https.proxy_host = "proxy.example.com" + https.proxy_port = 8080 + https.proxy_user = "username" + https.proxy_password = "password" + + Replace the placeholders with your actual proxy server details: + + - `proxy.example.com`: Your proxy server address. + - `8080`: Your proxy server port. + - `username`: Your proxy username (if required). + - `password`: Your proxy password (if required). + +4. **Save and Close the File** + + Save the changes and exit the text editor. + +5. **Verify the Configuration** + + Run the PHP CLI command again: + + .. code-block:: bash + + php occ app_api:app:register + + It should now be able to access the internet through the proxy. + +**Note:** Not all PHP functions respect the proxy settings in `php.ini`. If issues persist, consider using system-wide environment variables. + +Method 2: Set System-Wide Environment Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. **Edit Shell Profile** + + For a permanent solution, add the proxy settings to the system-wide environment variables. Open the `/etc/environment` file: + + .. code-block:: bash + + sudo nano /etc/environment + +2. **Add Proxy Environment Variables** + + Add the following lines to the file: + + .. code-block:: bash + + http_proxy="http://proxy.example.com:8080" + https_proxy="http://proxy.example.com:8080" + + # If your proxy requires authentication: + http_proxy="http://username:password@proxy.example.com:8080" + https_proxy="http://username:password@proxy.example.com:8080" + + Replace the placeholders with your actual proxy details. + +3. **Apply the Changes** + + Log out and log back in, or reboot the system to apply the changes. + +4. **Verify the Configuration** + + Run the command again: + + .. code-block:: bash + + php occ app_api:app:register --force-scopes test-deploy docker_socket_proxy --info-xml https://raw.githubusercontent.com/cloud-py-api/test-deploy/main/appinfo/info.xml --test-deploy-mode --no-ansi --no-warnings + + It should now work without connectivity issues. + +**Note:** This method sets the proxy settings for all users and applications on the system. + +Troubleshooting +--------------- + +- **Incorrect Proxy Details** + + Ensure all proxy details are correct. Incorrect hostnames, ports, or credentials will prevent connectivity. + +- **Environment Variables Not Loaded** + + Make sure the environment variables are correctly loaded. A system reboot or re-login may be necessary. + +- **Firewall Restrictions** + + Verify with your network administrator that your system is allowed to access the internet through the proxy. + +Contact Support +--------------- + +If you've followed these steps and still experience issues, please contact our support team for further assistance. diff --git a/developer_manual/exapp_development/faq/DockerContainerRegistry.rst b/developer_manual/exapp_development/faq/DockerContainerRegistry.rst new file mode 100644 index 000000000..ef77a512a --- /dev/null +++ b/developer_manual/exapp_development/faq/DockerContainerRegistry.rst @@ -0,0 +1,8 @@ +Docker Container Registry +========================= + +How to use a private Docker container registry with authentication? +******************************************************************* + +Currently, we don't support the authentication for Docker container registry. +The ExApp images must be publicly available. diff --git a/developer_manual/exapp_development/faq/DockerSocketProxy.rst b/developer_manual/exapp_development/faq/DockerSocketProxy.rst new file mode 100644 index 000000000..3df99427b --- /dev/null +++ b/developer_manual/exapp_development/faq/DockerSocketProxy.rst @@ -0,0 +1,56 @@ +Docker Socket Proxy +=================== + +The recommended way to setup AppAPI Deploy daemon +is to use our `Docker Socket Proxy implementation `_. + +Nextcloud AppAPI DSP +-------------------- + +Nextcloud AppAPI DSP (Docker Socket Proxy) - is a simple Docker container that provides a secure way to access the Docker Engine API and ExApps. +It is secured with haproxy Basic authentication. +There are two parts of reverse proxy configuration: + +- HaProxy config for `Docker Engine API `_ +- HaProxy config for `ExApps `_ + +.. note:: + + For remote Docker Socket Proxy setup, it should expose the ports on the host. + + +.. _faq_nextcloud-aio-docker-socket-proxy: + +Nextcloud AIO +------------- + +Nextcloud AIO implements `Docker Socket Proxy container `_ which automatically setting up, +you just need to tick the checkbox in AIO configuration interface to enable it. +AppAPI automatically creates the default Deploy daemon configuration in Nextcloud AIO. + +See :ref:`nextcloud-in-docker-aio-all-in-one` for more details. + +.. note:: + + Nextcloud AIO is not limited to its default Deploy daemon. + You can setup any other Deploy daemon (local or remote) to use it in AppAPI. + + +Other implementations +--------------------- + +Our implementation is inspired by `Tecnativa Docker Socket Proxy `_, +by default, it restricts access to the required by AppAPI Docker Engine APIs. +In this case, you will have to enable these APIs via the environment variables: + +- ``IMAGES=1`` +- ``CONTAINER=1`` +- ``POST=1`` + +.. note:: + + For local Deploy daemon setup other implementations of Docker Socket Proxy may be enough. + But for remote Deploy daemon setup, we recommend using our DSP, + as `we allow `_ only the Docker Engine APIs we actually use in AppAPI, + and it is additionally secured with haproxy authentication. + diff --git a/developer_manual/exapp_development/faq/GpuSupport.rst b/developer_manual/exapp_development/faq/GpuSupport.rst new file mode 100644 index 000000000..3c350ddb8 --- /dev/null +++ b/developer_manual/exapp_development/faq/GpuSupport.rst @@ -0,0 +1,28 @@ +GPU support +----------- + +How to enable GPU support for the Deploy daemon? +************************************************ + +To enable GPU support, you have to specify the GPU compute device when registering the Deploy daemon configuration. + +In this way, by default, AppAPI will create ExApp containers with request to the Docker Engine to attach all available GPU devices. +This also involves the specific ExApp supporting work with GPU internally +and the necessary Docker runtime toolkits installed on the Deploy daemon host: + +- For NVIDIA, refer to the `NVIDIA Docker configuration docs `_. +- For AMD, refer to the `ROCm Docker configuration docs `_. + +.. note:: + + If you encounter any issues with GPU support, it is highly dependent on the specific GPU device, + software libraries and therefore ExApps support of different hardware, or other factors. + Please, feel free to ask for help by creating an issue. + + +How to limit the number of GPUs per ExApp? +****************************************** + +Currently, there is no such configuration option. +AppAPI attaches all available GPU devices to each ExApp container on the same Deploy daemon. + diff --git a/developer_manual/exapp_development/faq/Scaling.rst b/developer_manual/exapp_development/faq/Scaling.rst new file mode 100644 index 000000000..79c1325c6 --- /dev/null +++ b/developer_manual/exapp_development/faq/Scaling.rst @@ -0,0 +1,22 @@ +Scaling +======= + +AppAPI delegates the scaling task to the ExApps itself. +This means, that the ExApp must be designed in a way to be able to scale vertically. +As for the horizontal scaling, currently, it is not possible. +Except, for example, the Server-Workers architecture, is a good way to support basic scaling capabilities, +where the Server is your ExApp and the Workers are the external machines that can work with the ExApp +using Nextcloud user authentication. +Aadditional clients (or workers) can be (optionally) added (or attached) to the ExApp +to increase the capacity and performance. + + +GPUs scaling +------------ + +Currently, if Deploy daemon configured with GPUs available, +AppAPI by default will attach all available GPU devices to each ExApp container on this Deploy daemon. +This means, that these GPUs are shared between all ExApps on the same Deploy daemon. +Therefore, for the ExApps that require GPU and uses it heavily, +it is recommended to have a separate Deploy daemon (host) for them. + diff --git a/developer_manual/exapp_development/faq/Troubleshooting.rst b/developer_manual/exapp_development/faq/Troubleshooting.rst new file mode 100644 index 000000000..826e6a9d6 --- /dev/null +++ b/developer_manual/exapp_development/faq/Troubleshooting.rst @@ -0,0 +1,53 @@ +Troubleshooting +=============== + +This section describes common steps to troubleshoot specific issues. + + +How to troubleshoot networking issues? +-------------------------------------- + +Networking issues can be not so straightforward to identify and resolve. +Here are some common steps to verify the network configuration: + +- Verify that the Deploy daemon is running and accessible (AppAPI admin settings - Select Deploy daemon - Check connection). +- Verify the network mode and access levels, firewall, vpn, etc. +- Verify that Nextcloud is reachable from the Deploy daemon host +- Verify that the Deploy daemon host is reachable from the Nextcloud host +- Verify that Nextcloud is reachable from the ExApp container +- Verify if there is no DNS resolution issues +- Verify is there is no SSL certificate issues +- If there are HTTP 401 Unauthorized errors, check the ExApp (``docker logs nc_app_``) / Nextcloud logs, on which API route it fails to authenticate, try to re-enable AppAPI and re-install the ExApp. + +.. note:: + If your case is not documented here, or doesn't exists on GitHub issues, + please feel free to ask it by creating an issue in the `AppAPI repository `_. + + +ExApp deployment issues +----------------------- + +The deployment issues questions are covered in the :ref:`Test Deploy ` section. +Generally speaking, there are three steps to find the proper error message to understand the problem: + +1. Check Nextcloud logs +2. Check ExApp container logs (available only if ExApp container is created and/or running) +3. Check Deploy daemon host logs (``journalctl -u docker.service``) +4. Check Docker Socket Proxy logs (if used, and if needed, e.g. for SSL or 401 errors check) + + +Failed to create volume +----------------------- + +If you encounter "Failed to create volume" error, please check the following: + +- Make sure that there is enough disk space on the host machine. +- Check the Docker system logs while reproducing the issue (``journalctl -u docker.service``). + + +ExApps management list of apps from AppStore is empty +----------------------------------------------------- + +This issue may occur if you are loading the ExApps management (or regular Apps management) page +frequently during the short period of time and therefore your IP can be blocked by the AppStore rate-limits protection. +Please, wait for a while and try again. diff --git a/developer_manual/exapp_development/faq/index.rst b/developer_manual/exapp_development/faq/index.rst new file mode 100644 index 000000000..49629b54e --- /dev/null +++ b/developer_manual/exapp_development/faq/index.rst @@ -0,0 +1,24 @@ +Frequently Asked Questions +========================== + +This section contains the most common or problematic questions +that users or developers may encounter when working with AppAPI. +It can be used as pointer to another parts of the documentation, as it usually refers to, +or provide a brief answer. + +.. note:: + + This section will be updated with time, as new questions arise. + If you have a question that is not listed here or the answer is not enough for you, please feel free to + ask it by creating an issue in the `AppAPI repository `_. + + +.. toctree:: + :maxdepth: 2 + + DockerContainerRegistry + DockerSocketProxy + GpuSupport + Scaling + BehindCompanyProxy + Troubleshooting diff --git a/developer_manual/exapp_development/index.rst b/developer_manual/exapp_development/index.rst new file mode 100644 index 000000000..bf8905cbc --- /dev/null +++ b/developer_manual/exapp_development/index.rst @@ -0,0 +1,29 @@ +================= +ExApp development +================= + +**ExApps** (short for "External Apps") are Nextcloud apps that are developed in another programming language (outside of PHP) using the AppAPI OCS API. +AppAPI is a project introduced by Nextcloud to revolutionize the process of application development within the Nextcloud ecosystem. + +Overview +-------- + +The main tasks of the AppAPI ecosystem are: + + * Providing a reliable and fast method for authenticating applications + * Supporting various application deployment options + * Offering a clear and straightforward application administration interface + * Ensuring a reliable implementation of all the necessary missing APIs for applications + * Supplying clear, understandable documentation and support on how to implement libraries in other programming languages for writing next-gen applications for Nextcloud + +If you have any questions or corrections regarding the documentation, +we would be glad to address them in discussions, incorporate corrections through pull requests, +and handle complex problems through issues. + +.. toctree:: + :maxdepth: 2 + + DevSetup + tech_details/index.rst + notes_for_developers/index.rst + faq/index.rst diff --git a/developer_manual/exapp_development/notes_for_developers/DevelopmentEnvironment.rst b/developer_manual/exapp_development/notes_for_developers/DevelopmentEnvironment.rst new file mode 100644 index 000000000..77f2884b4 --- /dev/null +++ b/developer_manual/exapp_development/notes_for_developers/DevelopmentEnvironment.rst @@ -0,0 +1,25 @@ +.. _DevelopmentEnvironment: + +Development environment +======================= + +The development environment for AppAPI first of all requires a default Nextcloud dev setup. +You can find more information on that in the `Nextcloud development environment docs `_. +The AppAPI dev setup steps listed :ref:`here `. + + +Deploy daemons types +-------------------- + +There are two types of Deploy daemons that can be used for development and testing of ExApp: + +1. ``manual_install``: This type of Deploy daemon is running manually in the host machine. + You can create it in AppAPI admin settings using template. + This is useful for development of ExApp, when you run your ExApp manually in the host. +2. ``docker_install``: This type of Deploy daemon is running in a Docker container. + +Docker Socket Proxy +------------------- + +For development and testing locally, the simplest is to use the `Nextcloud AppAPI DSP HTTP `_. + diff --git a/developer_manual/exapp_development/notes_for_developers/ExAppDevelopmentSteps.rst b/developer_manual/exapp_development/notes_for_developers/ExAppDevelopmentSteps.rst new file mode 100644 index 000000000..1d4e4b722 --- /dev/null +++ b/developer_manual/exapp_development/notes_for_developers/ExAppDevelopmentSteps.rst @@ -0,0 +1,124 @@ +.. _ExAppDevelopment: + +ExApp development +================= + +ExApp development process is similar to the development of the regular Nextcloud PHP app, +and should follow the same guidelines in terms of security, design and coding style (`ref `_) +based on your programming language standards. + +Despite the fact, that ExApp can be developed in any language, it's still recommended to have the understanding +of the Nextcloud `PHP request life cycle `_ and other basic concepts, +as they are usually similar to the ExApp backend to which Nextcloud communicates. + +You can think about ExApp like a microservice (Docker container) +that runs separately from Nextcloud on the Deploy daemon, which can be remote or local. +The communication between Nextcloud and ExApp is done via network secured with AppAPI authentication (:ref:`app_api_auth`). + +Lets go through the ExApp development steps briefly. + +0. Setting up the development environment +----------------------------------------- + +First of all, you need to have a Nextcloud dev setup, refer to :ref:`DevelopmentEnvironment` for more details. + +1. Starting from template +------------------------- + +Next step, is to setup the ExApp skeleton. +There are several ExApp examples available so you can have a look at them and start from. +The ExApp template and examples: + + - ``[Python]`` `App Skeleton `_ + - ``[Python]`` `UI Example Skeleton `_ + - ``[Python]`` `More complex ExApp UI example with 3rdparty service `_ + - ``[GoLang]`` `Go Lang ExApp example `_ + - etc. + +They contain the basic structure of the ExApp, including: + +- Dockerfile +- ExApp backend +- ExApp frontend +- Manual translations tools setup and example script to convert translation files to Nextcloud l10n format and for your programming language +- Some necessary GitHub workflows (e.g. `Docker image build workflows `_) + +More details are available in the :ref:`ExAppOverview` section. + + +3. Development +-------------- + +The development process basically contains from the following steps: + +- Implement the ExApp <-> Nextcloud :ref:`lifecycle methods `: + #. ``/heartbeat``: ExApp heartbeat method. + #. ``/init``: ExApp initialization method. + #. ``/enabled``: ExApp enable/disable method. +- Implement the ExApp backend API and logic. +- Implement the ExApp frontend (Nextcloud Vue.js app) [optional]. + + +4. Packaging +------------ + +The ExApp packaging can be done manually, or via GitHub actions. +It is recommended to use GitHub actions for packaging, +as it will automate the process of building the Docker image and pushing it to the Docker registry. +The GitHub action workflow for building Docker images can be found in the `3rdparty service example `_. + +4.1 Hardware acceleration +************************* + +If your ExApp work with GPUs, you should consider building different Docker images for each compute device. +Currently, there are 3 main compute devices to target with custom Docker images: + +- CPU (default, no specific tag) +- GPU: CUDA (NVIDIA) (``:-cuda``) +- GPU: ROCm (AMD) (``:-rocm``) + +.. note:: + + If the Deploy daemon configured with the GPU compute device, + AppAPI will try to pull the Docker image with the GPU support first (``:-``, `ref PR `_). + If the image is not found, AppAPI will try to pull the base (CPU) image (``:``). + + +Dockerfile +********** + +The Dockerfile is required to build the Docker image for the ExApp. +The guideline for writing the Dockerfile can be found in the `Dockerfile best practices `_. + +Short recommendations: + +1. Keep the Dockerfile as small as possible. +2. Use minimal base images to keep the image size small. +3. Place rarely changing instructions at the top of the Dockerfile to take advantage of Docker's caching mechanism. + + +Logging +******* + +The logs in Docker container are shown from the standard output and error streams. +To be able admin to see the important logs from ExApp container, +you should consider redirecting the logs to the standard output and standard error streams. +More info in `official docs for logging `_. + + +5. AppStore publishing +---------------------- + +Once the ExApp is ready, and the Docker image is available in the Docker registry, +you can follow `the AppStore publishing process `_. +It's the same as for the regular Nextcloud app, but with the requirement of :ref:`the ExApp specific fields ` in the ``appinfo/info.xml`` file. + + +6. Testing +---------- + +It is important to ensure that your ExApp works as expected. +We recommend to have different types of dev setup configuration to test all of them. +While the main development is done locally via ``manual_install``, you must also ensure that +the ExApp works correctly in Docker container with http and https Docker Socket proxy. + diff --git a/developer_manual/exapp_development/notes_for_developers/ExAppLifecycle.rst b/developer_manual/exapp_development/notes_for_developers/ExAppLifecycle.rst new file mode 100644 index 000000000..b4aa7970f --- /dev/null +++ b/developer_manual/exapp_development/notes_for_developers/ExAppLifecycle.rst @@ -0,0 +1,155 @@ +.. _ex_app_lifecycle: + +ExApp lifecycle +=============== + +The ExApp lifecycle is a set of communication rules (or protocol) between Nextcloud and ExApp. +They are required as for the microservice architecture of ExApp. +This section is an overview, more details on that here: :ref:`app_installation_flow`, :ref:`app_deployment`. + + +.. _ex_app_lifecycle_methods: + + +ExApp lifecycle methods +----------------------- + +When ExApp is being installed in Nextcloud, there are several lifecycle steps happening. +The ExApp lifecycle requires the following API endpoint handlers (order is preserved): + + - 0. ``healthcheck``: Docker container healthcheck. + - 1. ``/heartbeat``: **[required]** ExApp heartbeat handler. + - 2. ``/init``: **[optional]** ExApp initialization handler. + - 3. ``/enabled``: **[required]** ExApp enable/disable handler. + + +Healthcheck +*********** + +Docker allows you to define a custom healthcheck script for your container (specified in the Dockerfile). +You can define here if needed custom container startup logic. + +.. note:: + + AppAPI healthcheck timeout is 15 minutes. + + +Heartbeat +********* + +The ``GET /heartbeat`` method is called periodically by Nextcloud to check the ExApp health status, +if its webserver is running and recieving requests. + +URL: ``GET http://localhost:2345/heartbeat`` + +AppAPI expects a response with HTTP status 200. +This step fails if the ExApp does not respond within 10 minutes. + +.. note:: + + This endpoint should be available **without AppAPIAuth authentication**. + There is a 10 minutes timeout for the ExApp to startup and respond to the ``/heartbeat`` request. + + +.. _ex_app_lifecycle_init: + + +Init +**** + +The ``POST /init`` endpoint is called after the ExApp is enabled in Nextcloud. +This is a trigger for ExApp to start its initialization process, e.g. downloading models, starter data, etc. + +.. note:: + + Default init timeout (``init_timeout``) is 40 minutes. It can be changed by admin in AppAPI settings + or via CLI command ``occ config:app:set app_api init_timeout --value 40 --type mixed``. + +URL: ``POST http://localhost:2345/init`` + +AppAPI expects a response with HTTP status 200. + +.. note:: + + If ExApp doesn't not implement ``/init`` endpoint and AppAPI receives ``HTTP 501 NOT IMPLEMENTED`` or ``HTTP 404 NOT FOUND`` response, + AppAPI enables the ExApp. + +The ExApp should update the init progress via the ``PUT /ocs/v2.php/apps/app_api/ex-app/status`` API request, +with ``{ "progress": }`` payload. + + +Enabled +******* + +The ``PUT /enabled?enabled=1|0`` method is called when the ExApp is enabled or disabled in Nextcloud. +The ``enabled`` query parameter is used to determine the ExApp state: 1 - enabled, 0 - disabled. + + +- ``PUT http://localhost:2345/enabled?enabled=1`` - enable ExApp, during this call ExApp should register all needed APIs +- ``PUT http://localhost:2345/enabled?enabled=0`` - disable ExApp, during this call ExApp should unregister all APIs + +AppAPI expects a response with HTTP status 200. Any other status code will be considered as an error. + +.. note:: + + AppAPI timeout for the ``enabled`` handler is 30 seconds. + + +ExApp lifecycle scheme +---------------------- + +Let's review a simple ExApp lifecycle scheme: + + +.. mermaid:: + + sequenceDiagram + participant Nextcloud + participant ExApp + loop Heartbeat + Nextcloud->>ExApp: HTTP GET /heartbeat + ExApp-->>Nextcloud: /heartbeat HTTP 200 + end + Nextcloud->>ExApp: HTTP POST /init + ExApp->>Nextcloud: /init HTTP OK 200 + loop Init + ExApp->>ExApp: Download models, starter data, etc. + ExApp-->>Nextcloud: PUT /ocs/v2.php/apps/app_api/ex-app/status { "progress": 50 } + end + Nextcloud->>ExApp: HTTP PUT /enabled?enabled=1 + ExApp-->>Nextcloud: Register all needed APIs via OCS API + ExApp->>Nextcloud: /enabled HTTP 200 + Nextcloud->>ExApp: HTTP PUT /enabled?enabled=0 + ExApp-->>Nextcloud: Unregister all APIs via OCS API + ExApp->>Nextcloud: /enabled HTTP 200 + + +Nextcloud-side ExApp lifecycle methods +-------------------------------------- + +The Nextcloud-side ExApp lifecycle methods are the OCS APIs. +You can find available AppAPI Nextcloud OCS APIs :ref:`here `. + +.. note:: + + ExApp should register all needed APIs during the ``enabled`` method call. + E.g. UI (:ref:`top-menu `, :ref:`filesactionmenu `), :ref:`occ commands `, etc. + + +AppAPI Authentication +--------------------- + +Nextcloud requests to the ExApp are secured with :ref:`AppAPIAuth `. +The ExApp should validate the authentication using the same algorithm as AppAPI does. + +.. note:: + + Is it up to the developer to apply the rate limits, bruteforce protection, and other security measures + to the ExApp API endpoints. + + +Cookies +******* + +Along with the AppAPIAuth, ExApp can utilize the Nextcloud cookies of the authenticated user, +who made the request to the ExApp. diff --git a/developer_manual/exapp_development/notes_for_developers/ExAppOverview.rst b/developer_manual/exapp_development/notes_for_developers/ExAppOverview.rst new file mode 100644 index 000000000..f67bfc9de --- /dev/null +++ b/developer_manual/exapp_development/notes_for_developers/ExAppOverview.rst @@ -0,0 +1,335 @@ +.. _ExAppOverview: + +ExApp overview +============== + +Basic concept of the AppAPI is to provide a way to develop an app for Nextcloud using any language. +In this way, the ExApp can be written in any language, in particular, the backend part. +Frontend is kept the same. You can think about ExApp as a microservice. + + +ExApp structure +--------------- + +The typical ExApp folder structure is the following: + +- **appinfo/**: contains the ExApp metadata, which is based on the regular `Nextcloud PHP appinfo `_, + but with additional new fields under the ``external-app`` key. +- **ex_app/**: the ExApp specific folder, which contains the ExApp frontend and backend parts. + - **lib/**: contains the ExApp backend part, which can be written in any language. + - **src/**: contains the ExApp frontend part, which is a regular Nextcloud Vue.js application, with small adjustments to the script loading paths (see :ref:`ExApp specific frontend changes `). + - **img/**: contains the ExApp images. + - **css/**: contains the ExApp CSS files. +- **l10n**: contains the :ref:`ExApp translations `. +- **translationfiles**: contains the source translation (``.po``, ``.mo``) files for the ExApp. +- **other folders or files**: depends on your case, e.g. screenshots, scripts, etc. + + +.. _ex_app_info_xml_metadata: + +ExApp metadata +************** + +The ```` info.xml tag is required for the ExApp metadata. +It should contain the following fields: + +.. code-block:: + + + + ghcr.io + cloud-py-api/skeleton + latest + + // deprecated and removed since AppAPI 3.2.0 + FILES + AI_PROVIDERS + ... + + false // deprecated since AppAPI 3.0.0 + + +- **docker-install**: contains the Docker image information for the ExApp. + - **registry**: the Docker registry where the image is stored. + - **image**: the Docker image name. + - **image-tag**: the Docker image tag (version tag). +- **scopes**: the list of the Nextcloud scopes that the ExApp requires (see :ref:`list of scopes `). +- **system**: (deprecated since AppAPI 3.0.0) a boolean value that indicates whether the ExApp is a system app or not. + + +Backend +------- + +The ExApp backend part can be implemented in any language and framework you want, +the only requirement here is to follow the microservice architecture and ExApp <-> Nextcloud :ref:`communication flow `. + +.. note:: + + There is a limitation of AppAPI ExApp proxy - the websocket connections are not supported. + +Each ExApp container have the environment variables set by AppAPI, you can find more about it :ref:`here `. + +Persistent storage +****************** + +For each ExApp, AppAPI creates a Docker volume (``nc_app__data``), that is attached to the ExApp container as a persistent storage. +It is available inside container under the ``/nc_app__data`` path or via ``APP_PERSISTENT_STORAGE`` env passed by AppAPI. + + +.. _ex_app_specific_frontend_changes: + +Frontend +-------- + +The ExApp frontend part is loaded only for :ref:`TopMenu entry `. +It is a regular Nextcloud Vue.js application with a small routing adjustment to the paths, +as they are being loaded via AppAPI proxy from the ExApp server. + +To simplify the usage, we declare a few constants: + +.. code-block:: + + export const EX_APP_ID = 'ui_example' + export const EX_APP_MENU_ENTRY_NAME = 'first_menu' + export const APP_API_PROXY_URL_PREFIX = '/apps/app_api/proxy' + export const APP_API_ROUTER_BASE = '/apps/app_api/embedded' + +The bootstrap of the Vue app (`UI Example boostrap `_) is changes as follows: + +.. code-block:: + + import Vue from 'vue' + import { translate, translatePlural } from '@nextcloud/l10n' + import { generateUrl } from '@nextcloud/router' + import { APP_API_PROXY_URL_PREFIX, EX_APP_ID } from './constants/AppAPI.js' + import { getRequestToken } from '@nextcloud/auth' + + Vue.prototype.t = translate + Vue.prototype.n = translatePlural + Vue.prototype.OC = window.OC + Vue.prototype.OCA = window.OCA + + __webpack_public_path__ = generateUrl(`${APP_API_PROXY_URL_PREFIX}/${EX_APP_ID}/js/`) // eslint-disable-line + __webpack_nonce__ = btoa(getRequestToken()) // eslint-disable-line + + +Frontend routing +**************** + +The frontend routing base URL is also adjusted to be loaded via AppAPI proxy. +For example, the vuex router has the following base URL configuration: + +.. code-block:: + + ... + const router = new VueRouter({ + mode: 'history', + base: generateUrl(`${APP_API_ROUTER_BASE}/${EX_APP_ID}/${EX_APP_MENU_ENTRY_NAME}`, ''), // setting base to AppAPI embedded URL + linkActiveClass: 'active', + ... + +The same applies to the frontend API requests to the ExApp backend API: + +.. code-block:: + + ... + axios.get(generateUrl(`${APP_API_PROXY_URL_PREFIX}/${EX_APP_ID}/some_api_endpoint`)) + ... + + +.. _ex_app_translations: + +L10n translations +----------------- + +Currently, only `manual translations `_ are supported. +To add support of your programming language from translations string extraction using Nextcloud translation tool, +you just need to add your file extensions to it `in createPotFile `_ +and down below adjust the ``--language`` and ``keyword`` parameters. +Our examples using translationtool adjusted in the same way: + +.. code-block:: + + diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php + index 42513563..8aa06618 100644 + --- a/translations/translationtool/src/translationtool.php + +++ b/translations/translationtool/src/translationtool.php + @@ -67,7 +67,7 @@ public function createPotFile() { + $this->createFakeFileForVueFiles(); + $this->createFakeFileForLocale(); + $translatableFiles = $this->findTranslatableFiles( + - ['.php', '.js', '.jsx', '.mjs', '.html', '.ts', '.tsx'], + + ['.php', '.js', '.jsx', '.mjs', '.html', '.ts', '.tsx', '.py'], + ['.min.js'] + ); + + @@ -79,6 +79,8 @@ public function createPotFile() { + $keywords = ''; + if (substr($entry, -4) === '.php') { + $keywords = '--keyword=t --keyword=n:1,2'; + + } else if (substr($entry, -3) === '.py') { + + $keywords = '--keyword=_ --keyword=_n:1,2'; + } else { + $keywords = '--keyword=t:2 --keyword=n:2,3'; + } + @@ -86,6 +88,8 @@ public function createPotFile() { + $language = '--language='; + if (substr($entry, -4) === '.php') { + $language .= 'PHP'; + + } else if (substr($entry, -3) === '.py') { + + $language .= 'Python'; + } else { + $language .= 'Javascript'; + } + +where we declaring the methods used in source code for translating strings. + +The ExApp translations are stored in the ``l10n`` folder in the ExApp root folder. +For Nextcloud side it still has to contain the files as for regular Nextcloud apps (.js and .json). +There ExApp translation files are copied to the Nextcloud server during installation (removed on uninstall), +and can be used to translate ExApp string on backend or frontend parts the same way as for PHP apps. + +.. note:: + + For the clustered Nextcloud setup, the ExApp translations must be also copied to the other Nextcloud instances, + if the apps folder is not shared between the instances. + It is done automatically only for the instance, where the installation is performed. + + +You might need to convert the translation files to the format that is used in your language. +And this can be done with simple bash script, as `in our example for Python `_: + + +.. code-block:: + + #!/bin/bash + + # This script is used to transform default translation files folders (translationfiles//*.(po|mo)) + # to the locale folder (locale//LC_MESSAGES/*.(po|mo)) + + cd .. + + # Remove the locale/* if it exists to cleanup the old translations + if [ -d "locale" ]; then + rm -rf locale/* + fi + + # Create the locale folder if it doesn't exist + if [ ! -d "locale" ]; then + mkdir locale + fi + + # Loop through the translation folders and copy the files to the locale folder + # Skip the templates folder + + for lang in translationfiles/*; do + if [ -d "$lang" ]; then + lang=$(basename $lang) + if [ "$lang" != "templates" ]; then + if [ ! -d "locale/$lang/LC_MESSAGES" ]; then + mkdir -p locale/$lang/LC_MESSAGES + fi + # Echo the language being copied + echo "Copying $lang locale" + cp translationfiles/$lang/*.po locale/$lang/LC_MESSAGES/ + cp translationfiles/$lang/*.mo locale/$lang/LC_MESSAGES/ + fi + fi + done + + + +Makefile +-------- + +It is recommended to follow our Makefile example with the default set of commands: + +.. note:: + + Makefile is written to work in the `nextcloud-docker-dev `_ dev setup. + +- ``help``: shows the list of available commands. +- ``build-push-cpu``: builds the Docker image for CPU and uploads it to the Docker registry. +- ``build-push-cuda``: builds the Docker image for CUDA and uploads it to the Docker registry. +- ``build-push-rocm``: builds the Docker image for ROCm and uploads it to the Docker registry. +- ``run``: installs the ExApp for Nextcloud latest via the ``occ app_api:app:register`` command, like from UI. +- ``register``: performs registration of running manually ExApp using the ``manual_install`` Deploy daemon. +- ``translation_templates``: execute translationtool.phar to extract translation strings from sources (frontend and backend). +- ``convert_translations_nc``: converts translations to Nextcloud format files (json, js). +- ``convert_to_locale``: copies translations to the common locale//LC_MESSAGES/.(po|mo). Depending on the language, you might need to adjust the script. + + +Example +******* + +Here is an example of regular ExApp Makefile: + +.. code-block:: + + .DEFAULT_GOAL := help + + .PHONY: help + help: + @echo "Welcome to Nextcloud Visionatrix. Please use \`make \` where is one of" + @echo " " + @echo " Next commands are only for dev environment with nextcloud-docker-dev!" + @echo " They should run from the host you are developing on(with activated venv) and not in the container with Nextcloud!" + @echo " " + @echo " build-push-cpu build image for CPU and upload to ghcr.io" + @echo " build-push-cuda build image for CUDA and upload to ghcr.io" + @echo " build-push-rocm build image for ROCm and upload to ghcr.io" + @echo " " + @echo " run install Visionatrix for Nextcloud Last" + @echo " " + @echo " For development of this example use PyCharm run configurations. Development is always set for last Nextcloud." + @echo " First run original 'Visionatrix', then run this Visionatrix and then 'make registerXX', after that you can use/debug/develop it and easy test." + @echo " Do not forget to change paths in 'proxy_requests' function to point to correct files for the frontend" + @echo " " + @echo " register perform registration of running Visionatrix-es into the 'manual_install' deploy daemon." + @echo " " + @echo " L10N (for manual translation):" + @echo " translation_templates extract translation strings from sources" + @echo " convert_translations_nc convert translations to Nextcloud format files (json, js)" + @echo " convert_to_locale copy translations to the common locale//LC_MESSAGES/.(po|mo)" + + .PHONY: build-push-cpu + build-push-cpu: + docker login ghcr.io + docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag ghcr.io/cloud-py-api/visionatrix:$$(xmlstarlet sel -t -v "//image-tag" appinfo/info.xml) --build-arg BUILD_TYPE=cpu . + + .PHONY: build-push-cuda + build-push-cuda: + docker login ghcr.io + docker buildx build --push --platform linux/amd64 --tag ghcr.io/cloud-py-api/visionatrix-cuda:$$(xmlstarlet sel -t -v "//image-tag" appinfo/info.xml) --build-arg BUILD_TYPE=cuda . + + .PHONY: build-push-rocm + build-push-rocm: + docker login ghcr.io + docker buildx build --push --platform linux/amd64 --tag ghcr.io/cloud-py-api/visionatrix-rocm:$$(xmlstarlet sel -t -v "//image-tag" appinfo/info.xml) --build-arg BUILD_TYPE=rocm . + + .PHONY: run + run: + docker exec master-nextcloud-1 sudo -u www-data php occ app_api:app:unregister visionatrix --silent --force || true + docker exec master-nextcloud-1 sudo -u www-data php occ app_api:app:register visionatrix --force-scopes \ + --info-xml https://raw.githubusercontent.com/cloud-py-api/visionatrix/main/appinfo/info.xml + + .PHONY: register + register: + docker exec master-nextcloud-1 sudo -u www-data php occ app_api:app:unregister visionatrix --silent --force || true + docker exec master-nextcloud-1 rm -rf /tmp/vix_l10n && docker cp l10n master-nextcloud-1:/tmp/vix_l10n + docker exec master-nextcloud-1 sudo -u www-data php occ app_api:app:register visionatrix manual_install --json-info \ + "{\"id\":\"visionatrix\",\"name\":\"Visionatrix\",\"daemon_config_name\":\"manual_install\",\"version\":\"1.0.0\",\"secret\":\"12345\",\"port\":9100,\"scopes\":[\"AI_PROVIDERS\", \"FILES\", \"USER_INFO\"], \"translations_folder\":\"\/tmp\/vix_l10n\"}" \ + --force-scopes --wait-finish + + .PHONY: translation_templates + translation_templates: + ./translationtool.phar create-pot-files + + .PHONY: convert_translations_nc + convert_translations_nc: + ./translationtool.phar convert-po-files + + .PHONY: convert_to_locale + convert_to_locale: + ./scripts/convert_to_locale.sh + diff --git a/developer_manual/exapp_development/notes_for_developers/index.rst b/developer_manual/exapp_development/notes_for_developers/index.rst new file mode 100644 index 000000000..f54b753cc --- /dev/null +++ b/developer_manual/exapp_development/notes_for_developers/index.rst @@ -0,0 +1,17 @@ +.. _notes_for_developers: + +Notes for Developers +==================== + +This section contains the most common information for ExApp developers, +grouped from other parts of documentation. + + +.. toctree:: + :maxdepth: 2 + + DevelopmentEnvironment + ExAppDevelopmentSteps + ExAppOverview + ExAppLifecycle + diff --git a/developer_manual/exapp_development/tech_details/ApiScopes.rst b/developer_manual/exapp_development/tech_details/ApiScopes.rst new file mode 100644 index 000000000..0ca1b7c35 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/ApiScopes.rst @@ -0,0 +1,50 @@ +.. _api_scopes: + +Api Scopes +========== + +.. warning:: + + ApiScopes are deprecated and removed since AppAPI 3.2.0. + +AppAPI design's focus on simplicity and necessity highlights the benefits of defining API scopes. +which simplify the development and integration of applications into the Nextcloud ecosystem. + +With the elimination of optional API scopes, the configuration process during installation becomes more streamlined. +Now, the Nextcloud administrator only needs to focus on the essential API groups, +making the application's setup and permissions handling more efficient and less prone to errors. + +The **info.xml** file continues to play a crucial role, listing all the `required` API groups an +application needs to function correctly. +This not only simplifies version updates, allowing for the seamless introduction of +new API groups or the discontinuation of obsolete ones, but also enhances the overall security and reliability +of the application by ensuring it only has access to necessary functionalities. + +Supported API Groups include: + +* ``2`` SYSTEM +* ``10`` FILES +* ``11`` FILES_SHARING +* ``30`` USER_INFO +* ``31`` USER_STATUS +* ``32`` NOTIFICATIONS +* ``33`` WEATHER_STATUS +* ``50`` TALK +* ``60`` TALK_BOT +* ``61`` AI_PROVIDERS +* ``62`` EVENTS_LISTENER +* ``63`` OCC_COMMAND +* ``110`` ACTIVITIES +* ``120`` NOTES +* ``200`` TEXT_PROCESSING +* ``210`` MACHINE_TRANSLATION +* ``9999`` ALL + +These groups, represented by intuitive names, ensure that applications have +tailored access to the functionalities they need, enhancing performance and user experience. +As Nextcloud evolves, this list of API groups will continue to grow, offering developers a wide array of tools +to create innovative and efficient applications. + +The streamlined approach to API scopes not only simplifies the application development process +but also aligns with best practices in software design, emphasizing clarity, security, and efficiency. +This refinement in the handling of API scopes reflects Nextcloud's commitment to providing a robust and developer-friendly platform. diff --git a/developer_manual/exapp_development/tech_details/Authentication.rst b/developer_manual/exapp_development/tech_details/Authentication.rst new file mode 100644 index 000000000..0d07e0226 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/Authentication.rst @@ -0,0 +1,91 @@ +.. _app_api_auth: + +Authentication +============== + +AppAPI introduces a distinct method of authentication for external apps. +This authentication relies on a shared secret between Nextcloud and the external app + +Authentication flow +^^^^^^^^^^^^^^^^^^^ + +1. ExApp sends a request to Nextcloud +2. Nextcloud passes request to AppAPI +3. AppAPI validates request (see `authentication flow in details`_) +4. Request is accepted/rejected + +.. mermaid:: + + sequenceDiagram + participant ExApp + box Nextcloud + participant Nextcloud + participant AppAPI + end + ExApp->>+Nextcloud: Request to API + Nextcloud->>+AppAPI: Validate request + AppAPI-->>-Nextcloud: Request accepted/rejected + Nextcloud-->>-ExApp: Response (200/401) + + +.. _auth-headers: + +Authentication headers +^^^^^^^^^^^^^^^^^^^^^^ + +Each ExApp request to secured API with AppAPIAuth must contain the following headers: + +1. ``AA-VERSION`` - minimal version of the AppAPI +2. ``EX-APP-ID``- ID of the ExApp +3. ``EX-APP-VERSION`` - version of the ExApp +4. ``AUTHORIZATION-APP-API`` - base64 encoded ``userid:secret`` + +Authentication flow in details +****************************** + +.. mermaid:: + :zoom: + + sequenceDiagram + autonumber + participant ExApp + box Nextcloud + participant Nextcloud + participant AppAPI + end + ExApp->>+Nextcloud: Request to API + Nextcloud->>Nextcloud: Check if AUTHORIZATION-APP-API header exists + Nextcloud-->>ExApp: Reject if AUTHORIZATION-APP-API header not exists + Nextcloud->>Nextcloud: Check if AppAPI app is enabled + Nextcloud-->>ExApp: Reject if AppAPI is not exists or disabled + Nextcloud->>+AppAPI: Validate request + AppAPI-->>AppAPI: Check if ExApp exists and enabled + AppAPI-->>Nextcloud: Reject if ExApp not exists or disabled + AppAPI-->>AppAPI: Validate shared secret from AUTHORIZATION-APP-API + AppAPI-->>Nextcloud: Reject if secret does not match + AppAPI-->>AppAPI: Check if user is not empty and active + AppAPI-->>Nextcloud: Set active user + AppAPI->>-Nextcloud: Request accepted/rejected + Nextcloud->>-ExApp: Response (200/401) + + +AppAPIAuth +^^^^^^^^^^ + +AppAPI provides ``AppAPIAuth`` attribute with middleware to validate requests from ExApps. +In your API controllers you can use it as an PHP attribute. + +AppAPI session keys +^^^^^^^^^^^^^^^^^^^ + +After successful authentication AppAPI sets `app_api` session key to ``true``. + +.. code-block:: php + + $this->session->set('app_api', true); + $this->session->set('app_api_system', true); // deprecated since AppAPI 3.0.0 + +.. note:: + + The Nextcloud server verifies this session key and allows **CORS protection** and **Two-Factor authentication** to be bypassed for requests coming from ExApps. + Also the rate limit is not applied to requests coming from ExApps. diff --git a/developer_manual/exapp_development/tech_details/Deployment.rst b/developer_manual/exapp_development/tech_details/Deployment.rst new file mode 100644 index 000000000..37b0faed2 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/Deployment.rst @@ -0,0 +1,159 @@ +.. _app_deployment: + +Deployment +========== + +Overview +-------- + +AppAPI ExApps deployment process in short consists of 2 steps: + +1. `DaemonConfig registration`_ +2. `ExApp registration`_ + +.. _occ_daemon_config_registration: + +DaemonConfig registration +------------------------- + +The first step is to register DaemonConfig, where your ExApps will be deployed. +Before that you will need to configure your Docker socket to be accessible by Nextcloud instance and webserver user. +In case of remote Docker Engine API, you will need to expose it so it is accessible by Nextcloud instance and import certificates. + +.. note:: + For now only Docker daemon ``accepts-deploy-id: docker-install`` is supported. + For development and manually deployed app in docker there is ``accepts-deploy-id: manual-install``. + +This can be done by ``occ`` CLI command **app_api:daemon:register**: + +.. code-block:: bash + + app_api:daemon:register [--net NET] [--haproxy_password PASSWORD] [--] + +Arguments +********* + + * ``name`` - unique name of the daemon (e.g. ``docker_local_sock``) + * ``display-name`` - name of the daemon (e.g. ``My Local Docker``, will be displayed in the UI) + * ``accepts-deploy-id`` - type of deployment (``docker-install`` or ``manual-install``) + * ``protocol`` - protocol used to connect to the daemon (``http`` or ``https``) + * ``host`` - host of the daemon (e.g. ``/var/run/docker.sock`` or ``host:port``) + * ``nextcloud_url`` - Nextcloud URL, Daemon config required option (e.g. ``https://nextcloud.local``) + +Options +******* + + * ``--net [network-name]`` - ``[required]`` network name to bind docker container to (default: ``host``) + * ``--haproxy_password PASSWORD`` - ``[optional]`` password if ``AppAPI Docker Socket Proxy`` is used + * ``--gpu`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``/dev/dri``) + +.. note:: + Common configurations are tested by CI in our repository, see `workflows on github `_. + +Example +******* + +Example of ``occ`` **app_api:daemon:register** command: + +.. code-block:: bash + + sudo -u www-data php occ app_api:daemon:register docker_local_sock "My Local Docker" docker-install http /var/run/docker.sock "https://nextcloud.local" --net nextcloud + + +ExApp registration +------------------ + +Second and final step is to deploy and register ExApp in Nextcloud on previously registered daemon. +This can be done by ``occ`` CLI command **app_api:app:register**: + +.. code-block:: bash + + app_api:app:register [--force-scopes] [--] + +Arguments +********* + + * ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container) + * ``daemon-config-name`` - unique name of the daemon (e.g. ``docker_local_sock``) + +Options +******* + + * ``--force-scopes`` **[optional]** - force scopes approval + * ``--info-xml INFO-XML`` **[optional]** - path to info.xml file with ExApp description (url or local absolute path) + * ``--json-info JSON-INFO`` **[optional]** - JSON with ExApp description + +.. warning:: + After successful deployment (pull, create and start container), there is a heartbeat check with 90 seconds timeout (will be configurable). + +Manual install for development +****************************** + +For development purposes, you can install ExApp manually. +There is a ``manual-install`` DeployConfig type, which can be used in case of development. +For ExApp registration with it you need to provide JSON app info or a path to app XML file. + +For all examples and applications we release we usually add manual_install command in it's makefile for easier development. + +.. code-block:: + + php occ app_api:app:register nc_py_api manual_install --json-info \ + "{\"id\":\"nc_py_api\",\"name\":\"nc_py_api\",\"daemon_config_name\":\"manual_install\",\"version\":\"1.0.0\",\"secret\":\"12345\",\"port\":$APP_PORT,\"scopes\":[\"SYSTEM\", \"FILES\", \"FILES_SHARING\", \"USER_INFO\", \"USER_STATUS\", \"NOTIFICATIONS\", \"WEATHER_STATUS\", \"TALK\"],\"system\":1}" \ + --force-scopes + +.. note:: **Deployment/Startup of App should be done by developer when ``manual-install`` DeployConfig type is used.** + +.. _ex_app_env_vars: + +Deploy env variables +******************** + +Deploy env variables are used to configure ExApp container. +The following env variables are required and built automatically: + + * ``AA_VERSION`` - AppAPI version + * ``APP_SECRET`` - generated shared secret used for AppAPI authentication + * ``APP_ID`` - ExApp appid + * ``APP_DISPLAY_NAME`` - ExApp display name + * ``APP_VERSION`` - ExApp version + * ``APP_HOST`` - host ExApp is listening on + * ``APP_PORT`` - port ExApp is listening on (randomly selected by AppAPI) + * ``APP_PERSISTENT_STORAGE`` - path to mounted volume for persistent data storage between ExApp updates + * ``NEXTCLOUD_URL`` - Nextcloud URL to connect to + +Application installation scheme +------------------------------- + +1. AppAPI deploys the application and launches it. +2. AppAPI for `N` seconds (default ``90``) checks the ``/heartbeat`` endpoint with ``GET`` request. +3. AppAPI sends a ``POST`` to the ``/init`` endpoint. + + .. note:: if ExApp do not implements ``/init`` endpoint and + AppAPI receives 501 or 404 status error, AppAPI enables the application by going to point 5. + +4. **ExApp** sends an integer from ``0`` to ``100`` to the OCS endpoint ``apps/app_api/apps/status`` indicating the initialization progress. After sending ``100``, the application is considered initialized. +5. AppAPI sends a PUT to the ``/enabled`` endpoint. + +ExApp info.xml schema +--------------------- + +ExApp info.xml (`example `_) file is used to describe ExApp params. +It is used to generate ExApp docker container and to register ExApp in Nextcloud. +It has the same structure as Nextcloud appinfo/info.xml file, but with some additional fields: + +.. code-block:: xml + + ... + + + ghcr.io + cloud-py-api/talk_bot + latest + + // deprecated since AppAPI 3.2.0 + TALK + TALK_BOT + + 0 // deprecated since AppAPI 3.0.0 + + ... diff --git a/developer_manual/exapp_development/tech_details/Glossary.rst b/developer_manual/exapp_development/tech_details/Glossary.rst new file mode 100644 index 000000000..9135c9706 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/Glossary.rst @@ -0,0 +1,14 @@ +Glossary +======== + +AppAPI brings out the following terms frequently used in the code: + +* ``ExApp`` (External App) - the app on another (from PHP) programming language, which uses AppAPI OCS API +* ``DaemonConfig`` - configuration of orchestration daemon (e.g. Docker) where ExApps are deployed +* ``DeployConfig`` - additional DaemonConfig options for orchestrator (e.g. network) and ExApps (nextcloud_url, host, etc.) +* ``ExAppConfig`` - similar to Nextcloud `app_config`, but for ExApps configuration +* ``ExAppPreferences`` - similar to Nextcloud `app_preferences`, user-specific settings for ExApps +* ``AppAPIAuth`` - AppAPI authentication +* ``ExAppScope`` - granted to ExApp scope group of access to API routes +* ``ExAppApiScope`` - pre-defined scope group of access to list of API routes +* ``FileActionsMenu`` - entry in files actions menu (context menu) diff --git a/developer_manual/exapp_development/tech_details/InstallationFlow.rst b/developer_manual/exapp_development/tech_details/InstallationFlow.rst new file mode 100644 index 000000000..c016dd84e --- /dev/null +++ b/developer_manual/exapp_development/tech_details/InstallationFlow.rst @@ -0,0 +1,112 @@ +.. _app_installation_flow: + +App Installation Flow +===================== + +Image Pulling(Docker) +--------------------- + +AppAPI **2.5.0+** will always first try to pull a docker image with a ``suffix`` equal to value of *computeDevice*. + +Let us remind you that ``computeDevice`` can take the following values: ``cpu``, ``cuda``, ``rocm`` + +The suffix will be added as follows: + +.. code:: + + return $imageParams['image_src'] . '/' . + $imageParams['image_name'] . '-' . $daemonConfig['computeDevice']['id'] . ':' . $imageParams['image_tag']; + +For ``cpu`` AppAPI will first try to get the image from ``ghcr.io/cloud-py-api/skeleton-cpu:latest``. +In case the image is not found, ``ghcr.io/cloud-py-api/skeleton:latest`` will be pulled. + +If you as an application developer want to have a custom images for any of these values, you can push that extended images to registry in addition to the based one. + +Heartbeat +--------- + +The first thing AppAPI does is deploy of the application. + +In the case of ``Docker``, this is: + +#. 1. performing an image pull +#. 2. creating container from the docker image +#. 3. if the container supports `healthcheck` - AppAPI waits for the `healthy` status +#. 4. waiting until the “/heartbeat” endpoint becomes available with a ``GET`` request + +The application, in response to the request "/heartbeat", should return json: ``{"status": "ok"}``. + +.. note:: The request to ``/heartbeat`` endpoint is made without AppAPI authentication. + +Init +---- + +.. note:: Starting from this point, all requests made by AppAPI contains :ref:`auth-headers`. + +After application is ready, which is determined by previous step, +AppAPI sends ``POST`` request to the ``/init`` application endpoint. + +*If the application does not need to carry out long initialization, it has an option to not implement "/init" endpoint, so +AppAPI will get 404 or 501 error on it's request, and consider that initialization is done and this section can be skipped.* + +In case you want to implement "/init" endpoint, your application should: + +1. In "/init" handler: Response with empty JSON on AppAPI call. +2. In background job: Send an ``OCS request`` to ``PUT /ocs/v1.php/apps/app_api/ex-app/status`` with the progress value. + +.. warning:: + + ``PUT /ocs/v1.php/apps/app_api/apps/status/$APP_ID`` is deprecated and will be removed in the future. + +Possible values for **progress** are integers from 1 to 100; +after receiving the value 100, the **application is considered initialized and ready to work**. + +If at the initialization stage the application has a critical error due to which its further operation is impossible, + +``"error": "some error"`` + +should be added to the ``OCS request`` for setting progress, +with a short explanation at what stage this error occurred. + +Example of request payload with error will look like this:: + + {"progress": 67, "error": "connection error to huggingface."} + +Enabled +------- + +After receiving **progress: 100** (*or when ExApp is not implementing "/init" endpoint*), AppAPI enables the application. + +To enable or disable the application, a PUT request is sent to the ``/enabled`` endpoint. + +.. note:: Unlike using a payload, this request utilizes a query parameter named ``enabled`` to specify the desired state. + +The ``enabled`` parameter accepts an integer value: + +* `1` to enable the application +* `0` to disable the application + +For example, to enable the application, the request would be:: + + PUT http://expapp:2432/enabled?enabled=1 + +Similarly, to disable the application, the request would be:: + + PUT http://expapp:2432/enabled?enabled=0 + +This approach ensures that the application's state can be easily toggled using a simple query parameter. + +.. note:: ``/enabled`` endpoint shares both **enabling** and **disabling**, + so app should determine what is going on using the ``enabled`` input parameter of the request. + +Inside ``/enabled`` handler application should register all actions related to the Nextcloud, like UI and all other stuff. + +Response for this request should contain:: + + {"error": ""} + +for success and if some error occur during **enabling**, it should be present and not be empty:: + + {"error": "i cant handle enabling"} + +This is all three steps involved in the applications installation flow. diff --git a/developer_manual/exapp_development/tech_details/Translations.rst b/developer_manual/exapp_development/tech_details/Translations.rst new file mode 100644 index 000000000..5b3ef0a54 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/Translations.rst @@ -0,0 +1,50 @@ +Translations +============ + +ExApps translations work in the `same way as for PHP apps `_ with a few adjustments +and differences. + +In short, you just have to provide a ``l10n/.js`` (for front-end) and ``l10n/.json`` (for back-end) files for your app. + + +Front-end +********* + +For the front-end part AppAPI will inject the current user's locale ``l10n/.js`` script, so that access to translated strings in kept the same as was before in PHP apps. + +.. note:: + + ExApp l10n files are included only on the ExApp UI pages (:ref:`Top Menu `), Files (for :ref:`FileAction `) and Settings (for :ref:`DeclarativeSettings `). + + +Back-end +******** + +For the back-end part of ExApp which can be written in different programming languages it is **up to the developer to decide** how to handle and translations files. +There is an example repository with translations: `UI example with translations `_. + + +Manual install +************** + +For ``manual-install`` type administrator will have to manually extract to the server's `writable apps directory `_ ``l10n`` folder of ExApp +(e.g. ``/path/to/apps-writable//l10n/*.(js|json)``). +This will allow server to access ExApp's strings with translations. + +.. note:: + + Only ``l10n`` folder must be present on the server side, ``appinfo/info.xml`` could lead to be misdetected by server as PHP app folder. + + + +Docker install +************** + +For ``docker-install`` type AppAPI will extract ``l10n`` folder to the server automatically during installation from ExApp release archive. + + +Translation tool +**************** + +To add support for your language in Nextcloud `translationtool `_ feel free to create an issue in the `nextcloud/docker-ci `_ repository +or open a pull request with the changes made in ``createPotFile`` function to extract and convert translation strings. diff --git a/developer_manual/exapp_development/tech_details/api/appconfig.rst b/developer_manual/exapp_development/tech_details/api/appconfig.rst new file mode 100644 index 000000000..5e8e83568 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/appconfig.rst @@ -0,0 +1,136 @@ +========= +AppConfig +========= + +ExApp AppConfig API is similar to the standard Nextcloud **appconfig** API. + +Set app config value +^^^^^^^^^^^^^^^^^^^^ + +Set or update ExApp config value. + +.. note:: when ``sensitive`` is not specified during updating value, it will be not changed to default. + +OCS endpoint: ``POST /apps/app_api/api/v1/ex-app/config`` + +Request data +************ + +.. code-block:: json + + { + "configKey": "key", + "configValue": "value" + "sensitive": "sensitive flag affecting the visibility of the value (0/1, default: 0)" + } + +Response data +************* + +On success, ExAppConfig object is returned. +On error OCS Bad Request is returned. + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data": + { + "id":1084, + "appid":"app_id", + "configkey":"key", + "configvalue":"value", + "sensitive":1 + } + } + } + +Get app config values +^^^^^^^^^^^^^^^^^^^^^ + +Get ExApp config values + +OCS endpoint: ``POST /apps/app_api/api/v1/ex-app/config/get-values`` + +Request data +************ + +.. code-block:: json + + { + "configKeys": ["key1", "key2", "key3"] + } + +Response data +************* + +List of ExApp config values are returned. + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data":[ + { + "configkey":"test_key", + "configvalue":"123" + } + ] + } + } + +Delete app config values +^^^^^^^^^^^^^^^^^^^^^^^^ + +Delete ExApp config values. + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ex-app/config`` + +Request data +************ + +.. code-block:: json + + { + "configKeys": ["key1", "key2", "key3"] + } + +Response +******** + +Returns the number of configuration values removed. + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data":1 + } + } diff --git a/developer_manual/exapp_development/tech_details/api/events_listener.rst b/developer_manual/exapp_development/tech_details/api/events_listener.rst new file mode 100644 index 000000000..042cc72f3 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/events_listener.rst @@ -0,0 +1,83 @@ +.. _events_listener: + +=============== +Events Listener +=============== + +This API allows you to listen to `Nextcloud events `_ + +Currently only **limited** numbers of events are supported. + +Please let us know if there are any specific event we should add support to. + +.. note:: + + Unlike PHP events, all information from events comes to ExApp **asynchronously**, more like a notification system + to no slow down the server. + +Register +^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/events_listener`` + +Params +****** + +.. code-block:: json + + { + "eventType": "node_event", + "actionHandler": "/action_handler_route" + "eventSubtypes": [], + } + +.. note:: ``eventSubtypes`` is an optional parameter, when it is not specified all event subtypes will be propagated to ExApp. + + Url in ``actionHandler`` is relative to the ExApp root, starting slash is not required. + +Unregister +^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/events_listener`` + +Params +****** + +To unregister EventsListener, you just need to provide an `eventType` of the registered EventsListener: + +.. code-block:: json + + { + "eventType": "node_event" + } + +Event payload +^^^^^^^^^^^^^ + +.. code-block:: json + + { + "event_type": "node_event", + "event_subtype": "NodeCreatedEvent", + "event_data": "associative array depending on `event_subtype`" + } + +Events types +^^^^^^^^^^^^ + +Node Events +*********** + +``node_event`` - events about File `Nodes` + +Supported event sub-types: + * ``NodeCreatedEvent`` + * ``NodeTouchedEvent`` + * ``NodeWrittenEvent`` + * ``NodeDeletedEvent`` + * ``NodeRenamedEvent`` + * ``NodeCopiedEvent`` + +For all Node events ``event_data`` contain key **target** which has the same format like in :ref:`FileActionsMenu payload ` + +For ``NodeCopiedEvent`` and ``NodeRenamedEvent`` there is also a ``source`` key in the same format. diff --git a/developer_manual/exapp_development/tech_details/api/exapp.rst b/developer_manual/exapp_development/tech_details/api/exapp.rst new file mode 100644 index 000000000..d3510d3ce --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/exapp.rst @@ -0,0 +1,139 @@ +===== +ExApp +===== + +OCS APIs for ExApp actions. + +Get ExApps list +^^^^^^^^^^^^^^^ + +Get list of installed ExApps. + +OCS endpoint: ``GET /apps/app_api/api/v1/ex-app/{list}`` + +There are two ``list`` options: + +- ``enabled``: list only enabled ExApps +- ``all``: list all ExApps + + +Response data +************* + +The response data is a JSON array of ExApp objects with the following attributes: + +.. code-block:: json + + { + "id": "appid of the ExApp", + "name": "name of the ExApp", + "version": "version of the ExApp", + "enabled": "true/false flag", + "last_check_time": "timestamp of last successful Nextcloud->ExApp connection check", + "system": "true/false flag indicating system ExApp", + } + +Set ExApp init progress +^^^^^^^^^^^^^^^^^^^^^^^ + +Used during ExApp :ref:`initialization step `. + +.. note:: + + AppAPIAuth required. + +OCS endpoint: ``PUT /apps/app_api/ex-app/status`` + +Request data +************ + +.. code-block:: json + + { + "progress": "progress value", + "error": "optional, error string message" + } + +Response data +************* + +Returns HTTP 200 on success, HTTP 404 - on error. + +Get Nextcloud URL +^^^^^^^^^^^^^^^^^ + +It might be necessary for ExApp to know (or update) the Nextcloud URL. + +OCS endpoint: ``GET /apps/app_api/api/v1/info/nextcloud_url`` + +Response data +************* + +Returns the base URL of the Nextcloud instance: + +.. code-block:: json + + { + "base_url": "http(s)://nextcloud.example.com" + } + + +Make Requests to ExApps +^^^^^^^^^^^^^^^^^^^^^^^ + +There are two endpoints for making requests to ExApps: + +1. Synchronous request: ``POST /apps/app_api/api/v1/ex-app/request/{appid}`` +2. Synchronous request with ExApp user setup: ``POST /apps/app_api/api/v1/ex-app/request/{appid}/{userId}`` + +Request data +************ + +The request data params are the same as in ``lib/PublicFunction.php``: + +.. code-block:: json + + { + "route": "relative route to ExApp API endpoint", + "method": "GET/POST/PUT/DELETE", + "params": {}, + "options": {}, + } + +.. note:: + + ``userId`` and ``appId`` is taken from url params + + +Response data +************* + +Successful request to ExApp OCS data response structure is the following: + +.. code-block:: json + + { + "status_code": "HTTP status code", + "body": "response data from ExApp", + "headers": "response headers from ExApp", + } + +If there is an error, the response object will have only an ``error`` attribute with the error message. + + +Get ExApp enabled status +^^^^^^^^^^^^^^^^^^^^^^^^ + +Return the enabled status of the authenticated ExApp. + +OCS endpoint: ``GET /apps/app_api/api/v1/ex-app/state`` + +.. note:: + + This endpoint can be called by ExApp even if it is disabled on the Nextcloud side, + and requires :ref:`AppAPIAuth `. + +Response data +************* + +Returns 1 if the ExApp is enabled, 0 if it is disabled. diff --git a/developer_manual/exapp_development/tech_details/api/fileactionsmenu.rst b/developer_manual/exapp_development/tech_details/api/fileactionsmenu.rst new file mode 100644 index 000000000..dbc4a55c8 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/fileactionsmenu.rst @@ -0,0 +1,155 @@ +.. _file_actions_menu_section: + +================= +File Actions Menu +================= + +FileActionsMenu is a simple API for registering entry to the file actions menu for ExApps. +AppAPI takes responsibility to register FileActionsMenu, ExApps needs only to register it in AppAPI. + +.. note:: + + FileActionsMenu rendered only for enabled ExApps. + +Register +^^^^^^^^ + +.. note:: + + With AppAPI 2.6.0 there is a new v2 OCS endpoint with redirect to ExApp UI support: + OCS endpoint: ``POST /apps/app_api/api/v2/ui/files-actions-menu``. + Old v1 is marked as deprecated. + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/files-actions-menu`` + + +Params +****** + +Complete list of params (including optional): + +.. code-block:: json + + { + "name": "unique_name_of_file_actions_menu", + "displayName": "Display name (for UI listing)", + "actionHandler": "/action_handler_route" + "mime": "mime of files where to display action menu", + "icon": "img/icon.svg", + "permissions": "permissions", + "order": "order_in_file_actions_menu", + } + +.. note:: Urls ``icon`` and ``actionHandler`` are relative to the ExApp root, starting slash is not required. + +Optional params +*************** + + * `permissions` - File permissions required to display action menu, default: **31** (all permissions) + * `order` - Order in file actions menu, default: **0** + * `icon` - Url to icon, default: **null** + * `mime` - One mime or mimes separated by commas, default: **file** + +Unregister +^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/files-actions-menu`` + +Params +****** + +To unregister FileActionsMenu, you just need to provide name of registered FileActionsMenu: + +.. code-block:: json + + { + "name": "unique_name_of_file_action_menu" + } + +.. _node_info: + +Action payload to ExApp +^^^^^^^^^^^^^^^^^^^^^^^ + +When FileActionsMenu invoked, AppAPI forwards action for handling to ExApp. +The following data is sent to ExApp FileActionsMenu handler from the context of action: + +.. code-block:: json + + { + "fileId": "123", + "name": "filename", + "directory": "relative/to/user/path/to/directory", + "etag": "file_etag", + "mime": "file_full_mime", + "fileType": "dir/file", + "mtime": "last modify time(integer)", + "size": "integer", + "favorite": "nc_favorite_flag", + "permissions": "file_permissions_for_owner", + "shareOwner": "optional, str", + "shareOwnerId": "optional, str", + "shareTypes": "optional, int", + "shareAttributes": "optional, int", + "sharePermissions": "optional, int", + "userId": "string", + "instanceId": "string", + } + +Redirect to ExApp UI page (top menu) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + Supported only for Nextcloud 28+. + +If you want to open some files in ExApp UI, your FileActionsMenu have to be registered using OCS v2 version (``/apps/app_api/api/v2/ui/files-actions-menu``). + +After that, AppAPI will expect in the JSON response of the ExApp ``action_handler`` +the ``redirect_handler`` - a relative path on the ExApp Top Menu page, +to which AppAPI will attach a ``fileIds`` query parameter with the selected file ids, for example: + +``/index.php/apps/app_api/embedded/ui_example/first_menu/second_page?fileIds=123,124,125``, + +where the ``first_menu`` is the name of the Top Menu ExApp UI page, +and the ``second_page`` relative route handled on the frontend routing of the ExApp, +the ``fileIds`` query parameter contains the selected file ids separated by commas. +After that you can get the files info via webdav search request, see `ui_example `_. + + +Request flow +^^^^^^^^^^^^ + +General workflow of ExApp based on FileActionsMenu. + +User action +*********** + +.. mermaid:: + + sequenceDiagram + User->>FileActionMenu: Press on registered ExApp action + FileActionMenu->>AppAPI: send action context payload + AppAPI->>ExApp: forward request to handler + ExApp->>AppAPI: handler accepted action status + AppAPI->>User: Alert (action sent or error) + + +Action results +************** + +File processing results could be stored next to initial file or anywhere else, +e.g. on configured location in ExApp settings (``appconfig_ex``) or ExApp user settings (``preferences_ex``). + +.. mermaid:: + + sequenceDiagram + ExApp->>Nextcloud: Upload result file + ExApp->>AppAPI: Send notification about action results + +Examples +^^^^^^^^ + +Here is a list of simple example ExApps based on FileActionsMenu: + +* `to_gif `_ - ExApp based on FileActionsMenu to convert videos to gif in place +* `upscaler_example `_ - ExApp based on FileActionsMenu to upscale image in place diff --git a/developer_manual/exapp_development/tech_details/api/index.rst b/developer_manual/exapp_development/tech_details/api/index.rst new file mode 100644 index 000000000..3e47fa801 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/index.rst @@ -0,0 +1,30 @@ +.. _app_api_nextcloud_apis: + +===================== +AppAPI Nextcloud APIs +===================== + +.. note:: + + AppAPIAuth is required for all AppAPI OCS APIs, except ``ExApp``. + +.. toctree:: + :maxdepth: 2 + + logging + appconfig + preferences + exapp + routes + utils + fileactionsmenu + topmenu + settings + notifications + events_listener + occ_command + talkbots + speechtotext + textprocessing + machinetranslation + other_ocs diff --git a/developer_manual/exapp_development/tech_details/api/logging.rst b/developer_manual/exapp_development/tech_details/api/logging.rst new file mode 100644 index 000000000..623422bcc --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/logging.rst @@ -0,0 +1,35 @@ +======= +Logging +======= + +There is a logging API that can be used to log messages from ExApps in Nextcloud. + +.. note:: + + You can retrieve Nextcloud `loglevel` for internal ExApp usage + from private `app_api` (after authentication) capabilities + +Send log message (OCS) +^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/log`` + +Request data +************ + +.. code-block:: json + + { + "level": "log_lvl(integer)", + "message": "message", + } + + +The possible value of ``log_lvl`` is described here: `Nextcloud Log level `_ + +Response data +************* + +If no error occurs, empty response with result code 200 is returned. +If ExApp is not found or disable, or the loglevel is invalid - OCS Bad Request is returned. + diff --git a/developer_manual/exapp_development/tech_details/api/machinetranslation.rst b/developer_manual/exapp_development/tech_details/api/machinetranslation.rst new file mode 100644 index 000000000..7c9fd27ad --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/machinetranslation.rst @@ -0,0 +1,82 @@ +=================== +Machine Translation +=================== + +AppAPI provides a Machine-Translation providers registration mechanism for ExApps. + +.. note:: + + Available since Nextcloud 29. + +Registering translation provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ai_provider/translation`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + "display_name": "Provider Display Name", + "from_languages": { + "en": "English", + "fr": "French", + }, + "to_languages": { + "en": "English", + "fr": "French", + }, + "action_handler": "/handler_route_on_ex_app", + "action_detect_lang": "/detect_lang_from_text_handler", + } + +.. note:: + + ``from_languages`` and ``to_languages`` are JSON object with language code as key and language name as value. + ``action_detect_lang`` is optional. If provided, server's translation manager will call this handler to detect language from text if no source lang provided, + for reference see `Providing Language detection `_. + + +Response +******** + +On successful registration response with status code 200 is returned. + +Unregistering translation provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ai_provider/translation`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + } + +Response +******** + +On successful unregister response with status code 200 is returned. + + +Report translation result (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``PUT /apps/app_api/api/v1/ai_provider/translation`` + +Request data +************ + +.. code-block:: json + + { + "task_id": "queued_task_id", + "result": "translated_text", + "error": "error_message_if_any", + } diff --git a/developer_manual/exapp_development/tech_details/api/notifications.rst b/developer_manual/exapp_development/tech_details/api/notifications.rst new file mode 100644 index 000000000..cde06b487 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/notifications.rst @@ -0,0 +1,63 @@ +============= +Notifications +============= + +AppAPI allows ExApps to send limited notifications to users. +ExApp can send simple notification using available `rich object strings `_. +More info about rich objects string can be found `here `_. + +Send notification (OCS) +^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/notification`` + +Request payload +*************** + +Example payload. + +.. code-block:: json + + { + "params": { + "object": "app_api", + "object_id": "app_api_id", + "subject_type": "app_api_ex_app", + "subject_params": { + "rich_subject": "Image {file} successfully upscaled!", + "rich_subject_params": { + "file": { + "type": "file", + "id": 123, + "name": "upscaled_image_name", + "path": "path/to/upscaled_image_name" + } + }, + "rich_message": "{user} checkout results!", + "rich_message_params": { + "user": { + "type": "user", + "id": "admin", + "name": "admin" + } + }, + "link": "http(s)://nextcloud.local/index.php/apps/files/?fileid=123" + } + } + } + + +Params +^^^^^^ + +Required payload params: + + * ``object`` - ``[required]`` should be set to default value, not used yet + * ``object_id`` - ``[required]`` should be set to default value, not used yet + * ``subject_type`` - ``[required]`` subject type should be set to default value, not used yet + * ``subject_params`` - ``[required]`` + * ``rich_subject`` - ``[optional]`` rich subject (title) string + * ``rich_subject_params`` - ``[optional]`` rich subject (title) params to replace rich objects in string + * ``rich_message`` - ``[optional]`` rich message string + * ``rich_message_params`` - ``[optional`` rich message params to replace objects in string + * ``link`` - absolute url to set for notification link diff --git a/developer_manual/exapp_development/tech_details/api/occ_command.rst b/developer_manual/exapp_development/tech_details/api/occ_command.rst new file mode 100644 index 000000000..46e09cb59 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/occ_command.rst @@ -0,0 +1,108 @@ +.. _occ_command: + +=========== +OCC Command +=========== + +This API allows you to register the occ (CLI) commands. +The principal is similar to the regular Nextcloud OCC command for PHP apps, that are working in context of the Nextcloud instance, +but for ExApps it is a trigger via Nextcloud OCC interface to perform some action on the External App side. + + +.. note:: + + Passing files directly as an input argument to the occ command is not supported. + +Register +^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/occ_command`` + +Params +****** + +.. code-block:: json + + { + "name": "appid:unique:command:name", + "description": "Description of the command", + "hidden": "1/0", + "arguments": [ + { + "name": "argument_name", + "mode": "required/optional/array", + "description": "Description of the argument", + "default": "default_value" + } + ], + "options": [ + { + "name": "option_name", + "shortcut": "s", + "mode": "required/optional/none/array/negatable", + "description": "Description of the option", + "default": "default_value" + } + ], + "usages": [ + "occ appid:unique:command:name argument_name --option_name", + "occ appid:unique:command:name argument_name -s" + ], + "execute_handler": "handler_route" + } + +For more details on the command arguments and options modes, +see the original docs for the Symfony console input parameters, which are actually being built from the provided data: +`https://symfony.com/doc/current/console/input.html#using-command-arguments `_ + + +Example +******* + +Lets assume we have a command `ping` that takes an argument `test_arg` and has an option `test-option`: + +.. code-block:: json + + { + "name": "my_app_id:ping", + "description": "Test ping command", + "hidden": 0, + "arguments": [ + { + "name": "test_arg", + "mode": "required", + "description": "Test argument", + "default": 123 + } + ], + "options": [ + { + "name": "test-option", + "shortcut": "t", + "mode": "none", + "description": "Test option", + } + ], + "usages": [ + "occ my_app_id:ping 12345", + "occ my_app_id:ping 12345 --test-option", + "occ my_app_id:ping 12345 -t" + ], + "execute_handler": "handler_route" + } + +Unregister +^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/occ_command`` + +Params +****** + +To unregister OCC Command, you just need to provide a command `name`: + +.. code-block:: json + + { + "name": "occ_command_name" + } diff --git a/developer_manual/exapp_development/tech_details/api/other_ocs.rst b/developer_manual/exapp_development/tech_details/api/other_ocs.rst new file mode 100644 index 000000000..23773d4a6 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/other_ocs.rst @@ -0,0 +1,20 @@ +Other OCS APIs +============== + +With AppAPI authentication it is possible for ExApps to use any other OCS APIs, that doesn't require OCP implementation: + +.. note:: + + To access these APIs they have to be supported by AppAPI (see :ref:`api_scopes`), + and ExApp have to require granted access (in ``info.xml``) to them accordingly. + +1. Calendar +2. Contacts +3. File System & Tags +4. Shares +5. Notifications +6. Users & Groups +7. User & Weather status +8. Activities +9. Notes +10. Etc. diff --git a/developer_manual/exapp_development/tech_details/api/preferences.rst b/developer_manual/exapp_development/tech_details/api/preferences.rst new file mode 100644 index 000000000..d7b36faf6 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/preferences.rst @@ -0,0 +1,138 @@ +=========== +Preferences +=========== + +ExApp preferences API is similar to the standard preferences API. +It's a user specific settings. + + +Set user config value +^^^^^^^^^^^^^^^^^^^^^ + +Set or update config value for **current authenticated user**. + +OCS endpoint: ``POST /apps/app_api/api/v1/ex-app/preference`` + +Request data +************ + +.. code-block:: json + + { + "configKey": "key", + "configValue": "value" + } + +Response data +************* + +On success ExAppPreference object is returned. +On error OCS Bad Request is returned. + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data": + { + "id":983, + "appid":"app_id", + "configkey":"test key", + "configvalue":"123", + "sensitive":0 + } + } + } + +Get user config values +^^^^^^^^^^^^^^^^^^^^^^ + +Get config values for **current authenticated user**. + +OCS endpoint: ``POST /apps/app_api/api/v1/ex-app/preference/get-values`` + +Request data +************ + +.. code-block:: json + + { + "configKeys": ["key1", "key2", "key3"] + } + +Response data +************* + +List of ExApp preferences values are returned. + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data":[ + { + "configkey":"test key", + "configvalue":"123" + }, + { + "configkey":"test key2", + "configvalue":"321" + } + ] + } + } + + +Delete user config values +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Delete config values for **current authenticated user**. + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ex-app/preference`` + +Request data +************ + +.. code-block:: json + + { + "configKeys": ["key1", "key2", "key3"] + } + +Response +******** + +.. code-block:: json + + { + "ocs": + { + "meta": + { + "status":"ok", + "statuscode":100, + "message":"OK", + "totalitems":"", + "itemsperpage":"" + }, + "data":2 + } + } diff --git a/developer_manual/exapp_development/tech_details/api/routes.rst b/developer_manual/exapp_development/tech_details/api/routes.rst new file mode 100644 index 000000000..afca4f2ae --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/routes.rst @@ -0,0 +1,47 @@ +.. _ex_app_routes: + +====== +Routes +====== + +Since AppAPI 3.0.0 ExApps have to declare their routes allowed to be accessed via the AppAPI ExApp proxy. + +.. note:: + + This routes check applied only for ExApp proxy (``/apps/app_api/proxy/*``). + + +Register +^^^^^^^^ + +During ExApp installation, the ExApp routes are registered automatically. +The routes must be declared in the ``external-app`` - ``routes`` tag of the ``info.xml`` file. + +Example +******* + +.. code-block:: + + + + .* + GET,POST,PUT,DELETE + USER + [] + [401, 500] + + + +where the fields are: + +- ``url``: the route to be registered on the ExApp side, can be a regex +- ``verb``: the HTTP verb that the route will accept, can be a comma separated list of verbs +- ``access_level``: the name of the access level required to access the route, PUBLIC - public access without auth, USER - Nextcloud user auth required, ADMIN - admin user required +- ``headers_to_exclude``: a json encoded string of an array of strings, the headers that the ExApp wants to be excluded from the request to it +- ``bruteforce_protection``: a json encoded string of an array of numbers, the HTTP status codes that must trigger the bruteforce protection + + +Unregister +^^^^^^^^^^ + +ExApp routes are unregistered automatically when the ExApp is uninstalling, or during the ExApp update before registering the new routes. diff --git a/developer_manual/exapp_development/tech_details/api/settings.rst b/developer_manual/exapp_development/tech_details/api/settings.rst new file mode 100644 index 000000000..b379ac8bf --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/settings.rst @@ -0,0 +1,211 @@ +.. _declarative_settings_section: + +==================== +Declarative Settings +==================== + +Starting from Nextcloud **29**, AppAPI provides the ability to display ex-application settings. +When admin or user changes some ex-app settings +they will be stored in the database and can be received using :doc:`preferences` or :doc:`appconfig` API. + +.. note:: + + Settings rendered only for enabled ExApps. + +.. warning:: + + ``section_id`` from **scheme** should be already registered by any PHP application. + + **AppAPI** provides two sections for that: ``ai_integration_team`` and ``declarative_settings``, you can use them. + +Register Settings +^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/settings`` + +Params +****** + +Complete list of params (including optional): + +.. code-block:: json + + { + "formScheme": "settings scheme" + } + +Unregister Menu Entry +^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/settings`` + +Params +****** + +.. code-block:: json + + { + "formId": "formId from scheme" + } + +Example of settings scheme in Python: + +.. code-block:: python + + { + "id": "settings_example", + "priority": 10, + "section_type": "admin", + "section_id": "ai_integration_team", + "title": "AppAPI declarative settings", + "description": "These fields are rendered dynamically from declarative schema", + "fields": [ + { + "id": "field1", + "title": "Multi-selection", + "description": "Select some option setting", + "type": 'multi-select', + "options": ["foo", "bar", "baz"], + "placeholder": "Select some multiple options", + "default": ["foo", "bar"], + }, + { + "id": "some_real_setting", + 'title': 'Choose init status check background job interval', + 'description': 'How often AppAPI should check for initialization status', + 'type': 'radio', + 'placeholder': 'Choose init status check background job interval', + 'default': '40m', + 'options': [ + { + 'name': 'Each 40 minutes', + 'value': '40m', + }, + { + 'name': 'Each 60 minutes', + 'value': '60m', + }, + { + 'name': 'Each 120 minutes', + 'value': '120m', + }, + { + 'name': 'Each day', + 'value': f"{60 * 24}m", + }, + ], + }, + { + 'id': 'test_ex_app_field_1', + 'title': 'Default text field', + 'description': 'Set some simple text setting', + 'type': 'text', + 'placeholder': 'Enter text setting', + 'default': 'foo', + }, + { + 'id': 'test_ex_app_field_1_1', + 'title': 'Email field', + 'description': 'Set email config', + 'type': 'email', + 'placeholder': 'Enter email', + 'default': '', + }, + { + 'id': 'test_ex_app_field_1_2', + 'title': 'Tel field', + 'description': 'Set tel config', + 'type': 'tel', + 'placeholder': 'Enter your tel', + 'default': '', + }, + { + 'id': 'test_ex_app_field_1_3', + 'title': 'Url (website) field', + 'description': 'Set url config', + 'type': url', + 'placeholder': 'Enter url', + 'default': '', + }, + { + 'id': 'test_ex_app_field_1_4', + 'title': 'Number field', + 'description': 'Set number config', + 'type': 'number', + 'placeholder': 'Enter number value', + 'default': 0, + }, + { + 'id': 'test_ex_app_field_2', + 'title': 'Password', + 'description': 'Set some secure value setting', + 'type': password', + 'placeholder': 'Set secure value', + 'default': '', + }, + { + 'id': 'test_ex_app_field_3', + 'title': 'Selection', + 'description': 'Select some option setting', + 'type': 'select', + 'options': ['foo', 'bar', 'baz'], + 'placeholder': 'Select some option setting', + 'default': 'foo', + }, + { + 'id': 'test_ex_app_field_4', + 'title': 'Toggle something', + 'description': 'Select checkbox option setting', + 'type': 'checkbox', + 'label': 'Verify something if enabled', + 'default': False, + }, + { + 'id': 'test_ex_app_field_5', + 'title': 'Multiple checkbox toggles, describing one setting, checked options are saved as an JSON object {foo: true, bar: false}', + 'description': 'Select checkbox option setting', + 'type': 'multi-checkbox', + 'default': {'foo': True, 'bar': True}, + 'options': [ + { + 'name':'Foo', + 'value': 'foo', + }, + { + 'name': 'Bar', + 'value': 'bar', + }, + { + 'name': 'Baz', + 'value': 'baz', + }, + { + 'name': 'Qux', + 'value': 'qux', + }, + ], + }, + { + 'id': 'test_ex_app_field_6', + 'title': 'Radio toggles, describing one setting like single select', + 'description': 'Select radio option setting', + 'type': 'radio', + 'label': 'Select single toggle', + 'default': 'foo', + 'options': [ + { + 'name': 'First radio', + 'value': 'foo' + }, + { + 'name': 'Second radio', + 'value': 'bar' + }, + { + 'name': 'Second radio', + 'value': 'baz' + }, + ], + }, + ] + } diff --git a/developer_manual/exapp_development/tech_details/api/speechtotext.rst b/developer_manual/exapp_development/tech_details/api/speechtotext.rst new file mode 100644 index 000000000..0c2669bca --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/speechtotext.rst @@ -0,0 +1,51 @@ +============== +Speech-To-Text +============== + +AppAPI provides a Speech-To-Text (STT) provider registration API for the ExApps. + +.. note:: + + Available since Nextcloud 29. + +Registering ExApp STT provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/provider/speech_to_text`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + "display_name": "Provider Display Name", + "action_handler": "/handler_route_on_ex_app", + } + + +Response +******** + +On successful registration response with status code 200 is returned. + +Unregistering ExApp STT provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/provider/speech_to_text`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + } + + +Response +******** + +On successful unregister response with status code 200 is returned. diff --git a/developer_manual/exapp_development/tech_details/api/talkbots.rst b/developer_manual/exapp_development/tech_details/api/talkbots.rst new file mode 100644 index 000000000..c6825629d --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/talkbots.rst @@ -0,0 +1,41 @@ +========= +Talk bots +========= + +AppAPI provides API for registering ExApps Talk bots. +This means that ExApps could be just as Talk bot or it could be as one of the options of the app. +Read more about Talk bots `here `_. + +Register ExApp Talk bot (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/talk_bot`` + +Request data +************ + +.. code-block:: json + + { + "name": "Talk bot display name", + "route": "/talk_bot_webhook_route_on_ex_app", + "description": "Talk bot description", + } + + +Unregister ExApp Talk bot (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To unregister the ExApp Talk bot, you will have to pass the route where the Talk bot is registered. + +OCS endpoint: ``DELETE /apps/app_api/api/v1/talk_bot`` + +Request data +************ + +.. code-block:: json + + { + "route": "/route_of_talk_bot" + } + diff --git a/developer_manual/exapp_development/tech_details/api/textprocessing.rst b/developer_manual/exapp_development/tech_details/api/textprocessing.rst new file mode 100644 index 000000000..a4a80802e --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/textprocessing.rst @@ -0,0 +1,72 @@ +=============== +Text-Processing +=============== + +AppAPI provides a Text-Processing providers registration mechanism for ExApps. + +.. note:: + + Available since Nextcloud 29. + +Registering text-processing provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ai_provider/text_processing`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + "display_name": "Provider Display Name", + "action_handler": "/handler_route_on_ex_app", + "task_type": "supported_task_type", + } + +.. note:: + + ``action_type`` is a class name of the Text-Processing task type that can be found in the list of supported task types. + +Response +******** + +On successful registration response with status code 200 is returned. + +Unregistering text-processing provider (OCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ai_provider/text_processing`` + +Request data +************ + +.. code-block:: json + + { + "name": "unique_provider_name", + } + +Response +******** + +On successful unregister response with status code 200 is returned. + + +Get list of supported Text-Processing task types (capabilities) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are limited number of Task Types that can be used for Text-Processing. +You can get list of supported Text-Processing task types from OCS capabilities. + +Response +******** + +.. code-block:: json + + { + "text_processing": { + "task_types": ["free_prompt", "headline", "summary", "topics"] + } + } diff --git a/developer_manual/exapp_development/tech_details/api/topmenu.rst b/developer_manual/exapp_development/tech_details/api/topmenu.rst new file mode 100644 index 000000000..22e572e1e --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/topmenu.rst @@ -0,0 +1,160 @@ +.. _top_menu_section: + +============== +Top Menu Entry +============== + +TopMenu is an API for registering entry in the Nextcloud Top Menu for ExApps. +AppAPI takes responsibility to register TopMenu and proxy all requests to ExApp. + +.. note:: + + TopMenu rendered only for enabled ExApps. + +Register Menu Entry +^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/top-menu`` + +Params +****** + +Complete list of params (including optional): + +.. code-block:: json + + { + "name": "unique_name_of_top_menu", + "displayName": "Display name", + "icon": "img/icon.svg", + "adminRequired": "0 or 1", + } + +.. note:: ``icon`` are relative to the ExApp root, starting slash is not required. + + +Optional params +*************** + + * `icon` - Url to icon, default: **null** + * `adminRequired` - Value indicating should be Entry visible to all or only to admins. + +Unregister Menu Entry +^^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/top-menu`` + +Params +****** + +To unregister TopMenu, you just need to provide name of registered TopMenu: + +.. code-block:: json + + { + "name": "unique_name_of_top_menu" + } + +Set Initial state +^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/initial-state`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_top_menu", + "key": "key_name", + "value": "array with value(s)", + } + +Remove Initial state +^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/initial-state`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_top_menu", + "key": "key_name", + } + +Add script +^^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/script`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_script", + "path": "Url to script, e.g.: js/ui_example-main", + "afterAppId": "optional value", + } + +.. note:: Url to script is relative to the ExApp root, starting slash is not required, + ".js" extension is not needed and will be appended automatically by server. + +Remove script +^^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/script`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_script", + "path": "Url to script", + } + +Add style +^^^^^^^^^ + +OCS endpoint: ``POST /apps/app_api/api/v1/ui/style`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_style", + "path": "Url to style, e.g.: css/my-style", + } + +.. note:: Url to style is relative to the ExApp root, starting slash is not required, + ".css" extension is not needed and will be appended automatically by server. + +Remove style +^^^^^^^^^^^^ + +OCS endpoint: ``DELETE /apps/app_api/api/v1/ui/style`` + +Params +****** + +.. code-block:: json + + { + "type": "top_menu", + "name": "unique_name_of_style", + "path": "Url to style", + } diff --git a/developer_manual/exapp_development/tech_details/api/utils.rst b/developer_manual/exapp_development/tech_details/api/utils.rst new file mode 100644 index 000000000..c9c3b8a97 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/api/utils.rst @@ -0,0 +1,30 @@ +====================== +Miscellaneous OCS APIs +====================== + +There are some system utils APIs required for ExApps internal logic. + + +Get list of NC users +^^^^^^^^^^^^^^^^^^^^ + +OCS endpoint: ``GET /apps/app_api/api/v1/users`` + +Response data +************* + +Returns a list of user IDs only. + +.. code-block:: json + + {"ocs": { + "meta": { + "status": "ok", + "statuscode": 100, + "message": "OK", + "totalitems": "", + "itemsperpage": "" + }, + "data": ["admin", "alice", "bob", "jane", "john"] + } + } diff --git a/developer_manual/exapp_development/tech_details/index.rst b/developer_manual/exapp_development/tech_details/index.rst new file mode 100644 index 000000000..6e6f7a063 --- /dev/null +++ b/developer_manual/exapp_development/tech_details/index.rst @@ -0,0 +1,13 @@ +Technical details +================= + +.. toctree:: + :maxdepth: 2 + + Glossary + InstallationFlow + ApiScopes + Deployment + Authentication + Translations + api/index.rst diff --git a/developer_manual/index.rst b/developer_manual/index.rst index 6203eb01f..2617df81b 100644 --- a/developer_manual/index.rst +++ b/developer_manual/index.rst @@ -18,6 +18,7 @@ Table of contents getting_started/index basics/index app_development/index + exapp_development/index server/index digging_deeper/index app_publishing_maintenance/index