Core Architecture

SOGo6-server is a RESTful API using the Flask framework.

SOGo 6 web application code is under the package app

Start

  • app/run.py: init and check SOGo state, set the index endpoint, has the main function to create the Flask app

  • app/init.py: creates the Flask app, sets the swagger, sets global before_request and after_request.

  • app/service.py: contains the global cache object (and any future global service)

Core

The goal of SOGo 6 is to be modular to easily get new features or services. As such, the code is mainly separated between 4 categories:

  • API: defines the endpoints, the request or response schema.

  • Manager: requests external services (database, dovecot, ldap…​)

  • Module: Uses the manager to read or write data. Contains the main logic of any operation

  • Interface: Link between API and Module; Calls the right module, formats the answer and status code for the API. Also catches exceptions.

SOGo 6 structure

Rules

  • An API can only import one Interface

  • One API implies one dedicated Interface

  • Interface must return ready-to-use response (meaning data + http status code)

  • Interface can only import the modules it needs, can be one or several.

  • ONLY Interface catches RequestException.

  • Interface uses method create_api_base_response to format response (app/utils/api/ApiBaseResponse.py)

  • Module dynamically imports the proper managers. It can import one or several managers if needed (ex: ldap and sql if two kinds of user sources)

  • Manager does not import anything except utils/config. Manager must do its best to catch external library exceptions and either raise SOGo exception or let the module/interface decide what to do

Structure

  • app/api: The files of kind API, they can only import from interface, utils and config.

  • app/auth: The files to handle authentication, token, session in cache and set the class User.

  • app/config: The files to define SOGo 6 configuration, both parameters and database structure. Also contains the methods for initialization.

  • app/interface: The files of kind Interface, they can only import modules, utils and config

  • app/manager: The files of kind Manager, they can only import utils and config

  • app/module: The files of kind Module, they can only import manager, utils and config

  • app/utils: The files that define methods, classes and constants used everywhere. Can never import something from app.

API

APIs are defined in path app/api/<version>/

SOGo 6 has two distinct APIs: one for the webmail called "user" and one for the admin UI "admin". Admin API only has endpoints defined within app/api/<version>/admin/ All the others folders are for the user API.

Each API file must start by setting the blueprint for this api

from flask_smorest import Blueprint

blp = Blueprint("<name>", __name__, url_prefix="<url>")
  • <name> will be shown in the Swagger to regroup same endpoints together under user#Mail Folder

  • <url_prefix> is the url after /api/user/v1/<url_prefix>

Next step is to add a before_request to instantiate the interface

@blp.before_request
def init_mail_config() -> None:
    """
    Initialize the mail interface and any other required configuration for the request.

    Provide user_conf as either a single dict or a list of dicts (accounts).
    Here we provide a list: index 0 = primary, index 1 = secondary.
    """
    logger_api.debug("Calling before_request for ApiMailFolder")
    process: ProcessSetting = g.process_settings
    user_domain_settings: dict = g.user_domain_settings
    user: User = g.user

    interface_api = InterfaceApiMailFolder(
        process_setting=process,
        user_domain_settings=user_domain_settings,
        user=user
    )
    g.inter = interface_api