Action Service - OpenSlides/OpenSlides GitHub Wiki

TODO:

  • Note about inclusion into openslides-backend together with the presenter service
  • Scope of the service: modifying data.
  • How does sorting work
    • lists
    • trees

Interface

/**
 * Executes multiple actions in the context of the user given by the user_id.
 * There are two modes of execution:
 * atomic=true (default):
 *   All actions are validated in common, so if one action or one payload of
 *   one action fails, the request is aborted with an ActionException indicating
 *   the problematic action with both indices.
 *   => The whole request is handled atomically.
 * atomic=false:
 *   Each action is validated by it's own. If there is an error, the error must
 *   be reported via an ActionError in the ActionsResponse. The actions result
 *   is not written into the Datastore. It might raise an ActionException if the
 *   single write request to the Datastore fails (e.g. because of locking there)
 *
 * For general, non specific action-related, errors an ActionException is used.
 *
 * @throws ActionException
 */
handle_request(payload: Action[], user_id: Id, atomic?: boolean): ActionsResponse

interface Action {
    action: string;
    data: object[];
}

interface ActionsResponse {
    success: true;
    message: string;

    /**
     * This is a potentially double-array with entries for each action
     * and, if not null, an array for each data provided for each action.
     *
     * If an action does not produce a result, the inner array can be omitted and
     * null can be used. If the inner array is given, each entry must be an object
     * with the result (e.g. for a create action `{id: <the id>}`) or null.
     *
     * An empty inner array is the same as one filled with only null.
     *
     * E.g. for valid arrays (two actions with two data entries each):
     * - [null, null]
     * - [[], []]
     * - [null, [null, null]]
     * - [null, [{id: 2}, null]]
     * - [[{id: 2}, {id: 3}], [{id: 5}, {id: 8}]]
     *
     *
     * To report errors, use the ActionError format!
     **/
    results: (object[] | ActionError | null )[]
}

/**
 * If action_data_error_index is given, the error can be directly associated with the
 * respective action data. If not, the error is of general fashion and/or not directly
 * associated with a single action data.
 *
 * Note: ActionError can only be used if atomic=false.
 */
interface ActionError {
    success: false;
    message: string;
    action_data_error_index?: number;
}

/**
 * JSON resonse with a status code of !=200. If a specific action raised the error,
 * use the action_error_index and action_data_error_index to indicate the errored
 * action and data, respectively. If there were general errors, both indices must be
 * omitted or null.
 *
 * If the atomic flag was false in the request, it is not allowed to send
 * action-specific errors with this exception. It must be responded with an
 * ActionError through ActionsResponse (resulting in a status code of 200).
 */
Exception ActionException {
    success: false;
    message: string;
    action_error_index?: number;
    action_data_error_index?: number;
}

Sending emails

Available environment variables:

  • EMAIL_HOST
  • EMAIL_PORT
  • EMAIL_HOST_USER
  • EMAIL_HOST_PASSWORD
  • EMAIL_USE_SSL
  • EMAIL_USE_TLS
  • EMAIL_TIMEOUT
  • DEFAULT_FROM_EMAIL

Error handling in OS3:

The action user.send_invitation_email is mostly called as a bulk action. Please make sure, that exactly one connection to the email host is opened per request to the action service. All actions that access the email host must share the connection.

Naming conventions:

  • Payload: Everything that is sent from the client.
  • PayloadElement: A single Element of this list which contains the name of the action and the ActionData.
  • ActionData: The list of data that is supplied for a single action.
  • Instance (Action data element, ...): May have different names, depending on the context. Most of the time it reflects an instance of a model (e.g. for CUD actions)

Routes

There are 3 different kind of routes for using actions:

  • handle_request: The publicly accesible route from outside the proxy into our containerized OpenSlides installation. This handles the full payload in one transaction.
  • handle_separately: Same as above, but handles each payload element in its own transaction.
  • /internal/handle_request: Needs a password supplied in the AUTHORIZATION header, which is supplied via secrets to the backend and all using services. Can execute more actions than the public route, e.g. organization.initial_import.

Action Types

There are 3 different Action Types:

  • BACKEND_INTERNAL: This type of action is only usable inside the backend service source. They are a kind of helper actions, we use them without permissions.
  • STACK_INTERNAL: This type can only be used with the internal route (see above).
  • PUBLIC: These actions can be called from everywhere, but you need to authenticate, present a session token and the users permissions will be checked.
⚠️ **GitHub.com Fallback** ⚠️