Sahana Eden configuration usability report
==========================================

This document aims to provide comprehensive overview about status and usability of Sahana Eden configuration directives and modules, including the explanation of any deviation from the expected state, encountered errors and stack traces where applicable. Secondary function of this document is to provide a list of possible configuration directives and their expected types, values and effects. However the list is primarily collected using the directives present in *config.py* file in *default* template and is not exhaustive.

The configuration has been tested on Sahana Eden version `56afb71 (2017-08-31 01:10:50) <https://github.com/sahana/eden/tree/56afb712854515ef882f5ed0f5de84450ded4fd0>`_ using *default* template.

Legend
------
Each configuration directive is prepended with a tag representing its usability and readiness.

========== =======
Tag          Meaning
========== =======
**[O]**    Works as advertised, does not require additional configuration
**[+]**    Works with additional configuration explained in the description
**[!]**    Does not work. Short analysis of the problem attached
**[N/A]**  Untested or missing data
========== =======

Pre-Populate settings
---------------------

settings.base.guided_tour [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables guided tours (hints about commonly used features) accessible from Help menu. Requires additional lines in *tasks.cfg* to populate with default *Welcome tour*.

.. code-block:: text

    tour,config,guided_tour.csv,config.xsl
    tour,details,guided_tour_details.csv,details.xsl

| **Problem:** The tour does not show in the Help menu for unauthenticated user (as it is supposed to - see https://vimeo.com/67000529) and fails with multiple errors for authenticated user.

Authentication settings
-----------------------

settings.security.self_registration [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables user self-registration via login form.

settings.auth.registration_requires_verification [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables requirement for e-mail verification while registering a new user. Requires additional settings for SMTP server via ``settings.mail.*`` directives.

settings.auth.registration_requires_approval [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables requirement for administrator approval while registering a new user. Requires additional settings for SMTP server and administrators e-mail address via ``settings.mail.*`` directives.

settings.auth.registration_link_user_to [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {String: String}
| **Default:** ``None`` in code,

.. code-block:: python

    {"staff": T("Staff"),
    "volunteer": T("Volunteer"),
    "member": T("Member")}

| commented in default *config.py*
| **Description:** Shows checkbox list on registration form and allows linking user to human resource type. The default keys ``staff``, ``volunteer`` and ``member`` are the only valid ones as they are hardcoded throughout the code (mostly in *s3aaa.py*). The linking only creates appropriate linked record between user and organisation but all specific values need to be populated manually.

settings.auth.always_notify_approver [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables notification to administrator when ``settings.auth.registration_requires_approval = False`` and a new user registers and validates their account. Requires additional settings for SMTP server and administrators e-mail address via ``settings.mail.*`` directives.

settings.auth.opt_in_team_list [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List [String]
| **Default:** ``[]``
| **Description:** Adds user to defined team(s) if they checked the *Receive updates* checkbox in registration form. The teams have to be created manually or imported during pre-population phase.
| **Problem:** Enabling this option breaks user profile viewing on ``/eden/default/user/profile`` which fails with error 500 and stack trace

.. code-block:: pytb

    Traceback (most recent call last):
      File "/srv/sahana/gluon/restricted.py", line 227, in restricted
        exec ccode in environment
      File "/srv/sahana/applications/eden/controllers/default.py", line 1547, in <module>
      File "/srv/sahana/gluon/globals.py", line 417, in <lambda>
        self._caller = lambda f: f()
      File "/srv/sahana/applications/eden/controllers/default.py", line 608, in user
        form = auth.profile()
      File "applications/eden/modules/s3/s3aaa.py", line 1566, in profile
        ptable = s3db.pr_person
    UnboundLocalError: local variable 's3db' referenced before assignment

| The error can be corrected by initializing previously uninitialized variables via prepending line 1566 of *modules/s3/s3aaa.py* with

.. code-block:: python

    db = current.db
    s3db = current.s3db

settings.auth.opt_in_default [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays the checkbox for *Receive updates* as checked by default.

settings.auth.registration_requests_home_phone [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Home Phone* input field in user registration form. Doesn't do full validation and doesn't enforce country code like the *Contact* tab does.

settings.auth.registration_requests_mobile_phone [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Mobile Phone* input field in user registration form. Doesn't do full validation and doesn't enforce country code like the *Contact* tab does.

settings.auth.registration_mobile_phone_mandatory [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enforces the *Mobile Phone* field to be mandatory.

settings.auth.registration_requests_organisation [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays an *Organisation* dropdown in user registration form. The organizations have to be created manually, imported during pre-population phase or created via ``settings.auth.registration_organisation_default``.

settings.auth.registration_organisation_required [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enforces the *Organisation* dropdown to be mandatory.

settings.auth.registration_organisation_hidden [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Hides the *Organisation* dropdown (using JavaScript only) unless the user enters a non-whitelisted domain (i.e. domain not listed for any existing group or organisation).
| **Problem:** The *Organisation* dropdown stays hidden at all times. Moreover there does not seem to be any way how to bind a domain name to organization other than manual insert into *auth_organisation* table (the *Website* field in organisation definition is not related to this setting).

settings.auth.registration_organisation_default [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Pre-populates the *Organisation* dropdown in user registration form with defined value. The organisation will be created automatically if it doesn't exist.

settings.auth.registration_requests_organisation_group [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Coalition* dropdown in user registration form. Requires additional CSV with the values and additional line in *tasks.cfg* to import it.

.. code-block:: text

    org,group,org_group.csv,group.xsl

| See the template *CRMT* and its files *modules/templates/CRMT/org_group.csv*, *modules/templates/CRMT/org_group_membership_status.csv* and *modules/templates/CRMT/org_group_person_status.csv* for more details.

settings.auth.registration_organisation_group_required [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enforces the *Coalition* dropdown to be mandatory.

settings.auth.registration_requests_site [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Facility* dropdown in user registration form.

settings.auth.admin_sees_organisation [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** The value of ``settings.auth.registration_requests_organisation`` (which is ``False`` by default)
| **Description:** Displays an *Organisation* dropdown in user administration even when the organisation is not requested during registration via ``settings.auth.registration_organisation_required = True``.

settings.auth.show_utc_offset [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays a *UTC offset* field (time zone) in user profile. Original comment in *config.py* suggests that the field should show up also in registration form but it doesn't.

settings.auth.registration_roles [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary of Lists {Integer: [String]}
| **Default:** ``[]`` in code, ``{0: ["STAFF", "PROJECT_EDIT"]}`` commented in default *config.py*
| **Description:** Sets the default roles assigned to newly registered users. Dictionary key designates the realm that the list of roles applies to. ``0`` implies that the list is not realm restricted. List values are UUIDs stored in *auth_group* table. The roles have to exist before they can be referenced in this directive.

settings.auth.org_admin_to_first [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Sets the organisation administrator role for the first user which registers for given organisation. The *Organisation* dropdown must be requested in registration form via ``settings.auth.registration_requests_organisation = True``.

settings.auth.entity_role_manager [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables entity role manager via *Roles* tab in *Staff* for organisation admins. Entity role manager allows for per-organization and per-module role management.

settings.auth.realm_entity_types [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (String)
| **Default:**

.. code-block:: python

    ("org_group",
    "org_organisation",
    "org_office",
    "inv_warehouse",
    "pr_group")

| in code, ``("org_organisation",)`` commented in default *config.py*
| **Description:** Defines entity types to be used as realm entities for role management. Eg. user of one organisation won't have any rights in another organisation's records.

settings.auth.role_modules [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string: string}
| **Default:**

.. code-block:: python

    OrderedDict([
        ("staff", T("Staff")),
        ("vol", T("Volunteers")),
        ("member", T("Members")),
        ("inv", T("Warehouses")),
        ("asset", T("Assets")),
        ("project", T("Projects")),
        ("survey", T("Assessments")),
        ("irs", T("Incidents"))
    ])

| **Description:** Defines modules for entity role manager.
| **Problem:** User still has full access regardless of assigned roles.
| **TODO:** Check why everyone has admin roles to everything.

settings.auth.access_levels [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string: string}
| **Default:**

.. code-block:: python

    OrderedDict([
        ("reader", T("Reader")),
        ("data_entry", T("Data Entry")),
        ("editor", T("Editor")),
        ("super", T("Super Editor"))
    ])

| **Description:** Defines access levels for entity role manager.
| **Problem:** User still has full access regardless of assigned roles.
| **TODO:** Check why everyone has admin roles to everything.

settings.auth.record_approval [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables record approval by administrator.
| **TODO:** Which one? superadmin / org admin / entity manager?

settings.auth.record_approval_required_for [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (String)
| **Default:** ``[]`` in code, ``("org_organisation",)`` commented in default *config.py*
| **Description:** List of tables for which record approval is required.
| **TODO:** Seems that the approval is always automatically granted. Check why?

settings.auth.registration_requests_image [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a file selection button in registration form through which a new user is able to upload avatar image.

settings.auth.registration_volunteer [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Redirects newly-registered users to *Volunteers* page to be able to add extra details. Requires disabled new user verification and approval via ``settings.auth.registration_requires_verification = False`` and ``settings.auth.registration_requires_approval = False``.

settings.auth.terms_of_service [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Terms of Service* link and agreement checkbox in registration form. The terms need to exist as separate HTML page *modules/templates/\<template>/views/tos.html*. According to file *controllers/default.py* line 1522, custom views, such as *Terms of Service* are ignored while using the *default* template.

settings.auth.gmail_domains [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List [String]
| **Default:** ``[]``
| **Description:** Defines a list of domains in which users authenticate using Gmail account via SMTP. Requires *less secure applications* to be allowed on user's Gmail account via https://myaccount.google.com/lesssecureapps which is **strongly discouraged**. All values otherwise entered in registration form need to be filled in manually after first login, unless forced by other settings, eg. ``settings.auth.registration_organisation_default``.

settings.auth.office365_domains [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List [String]
| **Default:** ``[]``
| **Description:** Defines a list of domains in which users authenticate using Office 365 account via SMTP. All values otherwise entered in registration form need to be filled in manually after first login, unless forced by other settings, eg. ``settings.auth.registration_organisation_default``.

settings.auth.openid [!]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Allows user to login using OpenID account.  All values otherwise entered in registration form need to be filled in manually after first login, unless forced by other settings, eg. ``settings.auth.registration_organisation_default``.
| **Problem:** The ``/eden/default/user/login`` URL loads correctly but URL ``/eden/default/index`` fails with error 500 due to

.. code-block:: pytb

    Traceback (most recent call last):
      File "/srv/sahana/gluon/restricted.py", line 227, in restricted
        exec ccode in environment
      File "/srv/sahana/applications/eden/controllers/default.py", line 1547, in <module>
      File "/srv/sahana/gluon/globals.py", line 417, in <lambda>
        self._caller = lambda f: f()
      File "/srv/sahana/applications/eden/controllers/default.py", line 298, in index
        login_form = auth.login(inline=True)
      File "applications/eden/modules/s3/s3aaa.py", line 736, in login
        cas_user = cas.get_user()
      File "/srv/sahana/gluon/contrib/login_methods/extended_login_form.py", line 54, in get_user
        return self.alt_login_form.get_user()
      File "/srv/sahana/gluon/contrib/login_methods/openid_auth.py", line 178, in get_user
        if args[0] == 'logout':
    IndexError: list index out of range

| which implies a problem with *Web2py* framework. The line 178 in file *gluon/contrib/login_methods/openid_auth.py"* can be modified as follows

.. code-block:: python

    if args and args[0] == 'logout':

| After this fix, the URL ``/eden/default/index`` still fails with error 500 unless the user has cookie with key ``registered`` set. In case the cookie is not present, stack trace is just

.. code-block:: pytb

    Traceback (most recent call last):
      File "/srv/sahana/gluon/restricted.py", line 227, in restricted
        exec ccode in environment
      File "/srv/sahana/applications/eden/views/default/index.html", line 614, in <module>
    AttributeError: 'DIV' object has no attribute 'errors'

| which suggests some type confusion in variable ``login_form`` in file ``views/default/index.html`` or it's controller in file ``controllers/default.py``.
| The actual OpenID login fails with ``No pre-discovered information supplied.`` This may be caused by the fact that Sahana Eden is running on hostname unreachable from the internet.
| **TODO:** Check login on setup where the hostname is reachable from the internet.

settings.auth.password_changes [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Allows password change. If passwords are managed externally (OpenID / SMTP / LDAP), the recommended value is ``False``.

settings.auth.set_presence_on_login [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables presence records on login based on HTML5 geolocation API. Modern browsers require the page to be served via HTTPS to allow the geolocation API.
| **Problem:** Testing with both Chrome and Firefox browsers via both HTTP and HTTPS result in error 500 and following *Web2py* stack trace in terminal

.. code-block:: pytb

    ERROR:Rocket.Errors.Thread-9:Traceback (most recent call last):
      File "/srv/sahana/gluon/rocket.py", line 1337, in run
        self.run_app(conn)
      File "/srv/sahana/gluon/rocket.py", line 1838, in run_app
        output = self.app(environ, self.start_response)
      File "/srv/sahana/gluon/main.py", line 653, in app_with_logging
        ret[0] = wsgiapp(environ, responder2)
      File "/srv/sahana/gluon/main.py", line 564, in wsgibase
        return wsgibase(new_environ, responder)
      File "/srv/sahana/gluon/main.py", line 534, in wsgibase
        if request.body:
      File "/srv/sahana/gluon/globals.py", line 281, in body
        raise HTTP(400, "Bad Request - HTTP body is incomplete")
    HTTP: 400 BAD REQUEST

| The error suggests that miscalculated ``Content-Length`` HTTP header has been sent, but manual calculation confirms that the data sent by browser are valid and correct. This is likely a problem in *Web2py* framework and not in Sahana Eden.

settings.auth.ignore_levels_for_presence [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (String)
| **Default:** ``("L0",)``
| **Description:** Specifies a list of location levels to be ignored by presence records.
| **Problem:** Geolocation API enabled via ``settings.auth.set_presence_on_login`` doesn't working and renders this directive useless.

settings.auth.create_unknown_locations [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:**  Enables creation of new presence record locations if a user logs in from an unknown location. Warning: This may lead to many useless location entries.
| **Problem:** Geolocation API enabled via ``settings.auth.set_presence_on_login`` doesn't working and renders this directive useless.

Localization settings
---------------------

settings.L10n.languages [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string: string}
| **Default:** ``{"en": "English"}`` in code,

.. code-block:: python

    OrderedDict([
        ("ar", "العربية"),
        ("bs", "Bosanski"),
        ("en", "English"),
        ("fr", "Français"),
        ("de", "Deutsch"),
        ("el", "ελληνικά"),
        ("es", "Español"),
        ("it", "Italiano"),
        ("ja", "日本語"),
        ("km", "ភាសាខ្មែរ"),
        ("ko", "한국어"),
        ("mn", "Монгол хэл"),  # Mongolian
        ("my", "မြန်မာစာ"),       # Burmese
        ("ne", "नेपाली"),         # Nepali
        ("prs", "دری"),        # Dari
        ("ps", "پښتو"),         # Pashto
        ("pt", "Português"),
        ("pt-br", "Português (Brasil)"),
        ("ru", "русский"),
        ("tet", "Tetum"),
        ("tl", "Tagalog"),
        ("tr", "Türkçe"),
        ("ur", "اردو"),
        ("vi", "Tiếng Việt"),
        ("zh-cn", "中文 (简体)"),
        ("zh-tw", "中文 (繁體)"),
    ])

| in default *config.py*
| **Description:** Sets the list of languages visible in language toolbar and also list of GIS locations. Dictionary keys are ISO 639-1 codes (resp. ISO 639-2 where ISO 639-1 does not exist) - http://www.loc.gov/standards/iso639-2/php/code_list.php. Requires appropriate translation files to be present in *languages* directory. Note that there is a list of ISO 639-1 codes accepted by Sahana Eden as part of file *modules/s3/s3validators.py* starting on line 4286.

settings.L10n.default_language [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"en"``
| **Description:** Sets the default language for unauthenticated and newly registered users.

settings.L10n.display_toolbar [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** True
| **Description:** Shows the language toolbar

settings.L10n.utc_offset [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"+0000"``
| **Description:** Sets the default time zone for unauthenticated and newly registered users.

settings.L10n.date_format [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** Based on ``settings.L10n.default_language``

.. code-block:: python

    {"ar": "%d/%m/%Y",
    "bs": "%d.%m.%Y",
    "de": "%d.%m.%Y",
    "el": "%d/%m/%Y",
    "es": "%d/%m/%Y",
    "fr": "%d/%m/%Y",
    "hr": "%d.%m.%Y",
    "it": "%d/%m/%Y",
    "ja": "%Y/%m/%d",
    "km": "%d-%m-%Y",
    "ko": "%Y-%m-%d",
    "ne": "%d/%m/%Y",
    "prs": "%Y/%m/%d",
    "ps": "%Y/%m/%d",
    "pt": "%d/%m/%Y",
    "pt-br": "%d/%m/%Y",
    "ru": "%d.%m.%Y",
    "sr": "%d.%m.%Y",
    "sv": "%Y-%m-%d",
    "ta": "%d/%m/%Y",
    "th": "%d/%m/%Y",
    "tr": "%d.%m.%Y",
    "vi": "%d/%m/%Y",
    "zh-cn": "%Y-%m-%d",
    "zh-tw": "%Y/%m/%d"}

| unlisted codes fallback to ``"%Y-%m-%d"``
| **Description:** Sets the default date format for unauthenticated and newly registered users.

settings.L10n.time_format [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"%H:%M"``
| **Description:** Sets the default time format for unauthenticated and newly registered users.

settings.L10n.firstDOW [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``None``
| **Description:** Sets the first day in calendar. ``0`` = Sunday, ``1`` = Monday, ..., ``6`` = Saturday. Value ``None`` forces to use calendar default based on ``settings.L10n.default_language``. The calendar is a jQueryUI *Datepicker* component - see https://jqueryui.com/datepicker/.

settings.L10n.decimal_separator [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``","``
| **Description:** Sets the default decimal separator.

settings.L10n.thousands_separator [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``" "``
| **Description:** Sets the default thousand separator.

settings.L10n.default_country_code [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``1``
| **Description:** Sets the default country code for SMS gateway for telephone numbers without country code.
| **TODO:** Test with SMS gateway.

settings.L10n.mandatory_lastname [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** False
| **Description:** Enables requirement for last names (surnames), resp. a requirement to have a space in the name.

settings.L10n.religions [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string: string}
| **Default:**

.. code-block:: python

    {"none": T("none"),
    "christian": T("Christian"),
    "muslim": T("Muslim"),
    "jewish": T("Jewish"),
    "buddhist": T("Buddhist"),
    "hindu": T("Hindu"),
    "bahai": T("Bahai"),
    "other": T("other")}

| **Description:** Populates values for *Religion* dropdown in person details.

settings.L10n.translate_cms_series [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables display of translated strings for CMS (Content Management System) series.
| **Problem:** The setting does not seem to affect anything. It is referenced in file *modules/s3db/cms.py* on line 143 and file *controllers/cms.py* on line 535 where it is commented.

settings.L10n.translate_gis_layer [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of translated strings for GIS layer names in searches, filters, etc.

settings.L10n.translate_gis_location [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of translated strings for GIS location names in searches, filters, etc. Note that the language code must be a valid ISO 639-1 code accepted by Sahana Eden as listed in file *modules/s3/s3validators.py* starting on line 4286.

settings.L10n.name_alt_gis_location [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of alternative strings for GIS location names in searches, filters, etc.
| **TODO:** Figure out where are the names used.

settings.L10n.translate_org_organisation [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of translated strings for organisation names in searches, filters, etc. Note that the language code must be a valid ISO 639-1 code accepted by Sahana Eden as listed in file *modules/s3/s3validators.py* starting on line 4286.

settings.L10n.translate_org_site [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of translated strings for organisation site names in searches, filters, etc. Note that the language code must be a valid ISO 639-1 code accepted by Sahana Eden as listed in file *modules/s3/s3validators.py* starting on line 4286.

Finance settings
----------------

settings.fin.currencies [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string:string}
| **Default:**

.. code-block:: python

    {"EUR" : "Euros",
    "GBP" : "Great British Pounds",
    "USD" : "United States Dollars"}

| **Description:** Populates values for *Currency* dropdowns where applicable.

settings.fin.currency_default [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"USD"``
| **Description:** Sets the default currency. The value needs to exist in ``settings.fin.currencies``.

settings.fin.currency_writable [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** True
| **Description:** N/A
| **Problem:** This value is used only in file *modules/s3/s3fields.py* on line 1229 and seems to have no effect other that allowing the dropdown in HTML form to be selectable.

PDF settings
------------

settings.base.paper_size [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"A4"``
| **Description:** Sets the default paper size for reports. The only valid values seem to be ``"A4"`` and ``"Letter"``.

settings.ui.pdf_logo [!]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets the location to file containing logo displayed in PDF headers.
| **Problem:** The setting and assigned local variable is referenced twice in file *modules/s3/s3pdf.py* on lines 352 and 2864, yet the code does not seem to hit any of those lines while creating a PDF.

GIS settings
------------

settings.gis.spatialdb [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of spatial database extensions where applicable. Currently supports only *PostGIS*.

settings.gis.map_height [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** 600
| **Description:** Sets the map height in pixels.
| **Problem:** The value is ignored in embedded and fullscreen views in *Map* menu. The value is used also for map printing, but does not seem to be taken into account. Moreover map printing is discouraged due to security concerns. See ``settings.gis.print_button``.

settings.gis.map_width [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** 1000
| **Description:** Sets the map width in pixels.
| **Problem:** The value is ignored in embedded and fullscreen views in *Map* menu. The value is used also for map printing, but does not seem to be taken into account. Moreover map printing is discouraged due to security concerns. See ``settings.gis.print_button``.

settings.gis.countries [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List [String]
| **Default:** ``[]``
| **Description:** Restricts country selection in location widget to specified countries (eg. in *Staff* menu *Address* tab). The restriction can be overridden in specific contexts (eg. projects). Note that *Map* menu does not use location widget, therefore this setting does not apply to it.

settings.gis.geocode_imported_addresses [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``False`` (Note: This is a type mismatch)
| **Description:** Attempts to get latitude and longitude of addresses imported via CSV. Requires appropriate geocoder present in *modules/geopy/geocoders* directory. Currently, geocoders ``"bing"``, ``"dot_us"``, ``"geonames"``, ``"google"``, ``"googlev3"``, ``"mapquest"``, ``"openmapquest"``, ``"wiki_gis"``, ``"wiki_semantic"`` and ``"yahoo"`` exist.
| **TODO:** Test imports

settings.gis.map_selector [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays embedded map widget as selection tool in location widget (eg. in *Staff* menu *Address* tab). Note that *Map* menu does not use location widget, therefore this setting does not apply to it.

settings.gis.latlon_selector [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays *Latitude* and *Longitude* input fields in location widget (eg. in *Staff* menu *Address* tab). Note that *Map* menu does not use location widget, therefore this setting does not apply to it.

settings.gis.cluster_fill [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets fill color for clustered POI mark. The color is a hexadecimal RGB string.

settings.gis.cluster_label [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays number of POIs on clustered POI mark. The color is a hexadecimal RGB string.

settings.gis.cluster_stroke [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets stroke color for clustered POI mark.

settings.gis.select_fill [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets fill color for marked (hovered on) POI. The color is a hexadecimal RGB string.

settings.gis.select_stroke [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets stroke color for marked (hovered on) POI. The color is a hexadecimal RGB string.

settings.gis.display_L0 [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables fallback to country LatLon to show resources, if nothing better is available.
| **Problem:** Unused in code, not referenced in any module.

settings.gis.display_L1 [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables fallback to country LatLon to show resources, if nothing better is available.
| **Problem:** Unused in code, not referenced in any module.

settings.gis.lookup_code [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean in *s3cfg.py*, String in *config.py*, Dictionary in description of *s3cfg.py*
| **Default:** ``False``
| **Description:** Enables deduplication imported items via PCode (as alternative to Name)
| **TODO:** Figure out the actual type and function. Referenced in file *modules/s3db/gis.py* on line 5818.

settings.gis.menu [+]
^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``False`` (Note: This is a type mismatch)
| **Description:** Enables separate GIS configurations and map profiles, and simultaneously sets the menu label for them. Requires additional configuration via either *Menu* menu of *Map* module or database tables *gis_menu* and *gis_config*. See template *MAVC* and its file *modules/templates/MAVC/gis_config.csv* for more details.

settings.gis.marker_max_height [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** 35
| **Description:** Sets maximal height of a marker icon on a map.
| **Problem:** Settings does not seem to have any effect. Map markers still have the original size as defined by the image used.

settings.gis.marker_max_width [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** 30
| **Description:** Sets maximal width of a marker icon on a map.
| **Problem:** Settings does not seem to have any effect. Map markers still have the original size as defined by the image used.

settings.gis.duplicate_features [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables duplication of map markers and other features so that they show wrapped across the date line.
| **Problem:** Settings does not seem to have any effect. Map markers and other features are still displayed only once.

settings.gis.layer_metadata [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Allows using CMS (Content Management System) to provide metadata on map layers. The metadata are just CMS posts with text pertaining to respective map layers.
| **Problem:** The setting is referenced in file *modules/s3/s3gis.py* on line 9683 where it enables metadata-related controls if ``settings.gis.legend = "float"`` and the user has ``"MAP_ADMIN"`` privilege, which is then reflected in file *static/scripts/S3/s3.gis.js* on line 6824, however has effect only on WMS (Web Map Service) layers.

settings.gis.clear_layers [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays *Clear Layers* tool. If the option is set to ``True``, the tool is shown above map layer tree, but can also be set to ``"toolbar"`` (Note: This is a type mismatch) in which case it's displayed in the toolbar above map.
| **Problem:** The option does not have any effect due to a typo in file *static/scripts/S3/s3.gis.js* where on line 6824 both occurrences of ``options.clearlayers`` should be replaced by ``options.clear_layers``. After this error is fixed, the tool seems to work properly.

settings.gis.geolocate_control [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Zoom to Current Location* button in the map toolbar.

settings.gis.getfeature_control [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Get Feature Info* button on toolbar. Requires queryable WMS (Web Map Service) layer. Note: No such layer is present in any of supplied templates.

settings.gis.layer_properties [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Layer Properties* button in map layer tree. Note: No layer present in template *default* has any properties.

settings.gis.layer_tree_base [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Base Layers* tree in map layer tree.

settings.gis.layer_tree_overlays [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Overlays* tree in map layer tree.

settings.gis.label_overlays [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Overlays"``
| **Description:** Sets the label for *Overlays* tree in map layer tree.

settings.gis.layer_tree_expanded [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Defines if the map layer tree should be expanded when the page loads.

settings.gis.layer_tree_radio [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Defines if the features in custom folders (ie. others than *Base Layers* and *Overlays*) should be selectable using radio buttons. If set to default value ``False``, the selection is made using checkboxes, thus allowing selection of multiple features in the same folder.

settings.gis.legend [O]
^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays the map legend under map layer tree. The value can be also set to string ``"float"`` (Note: This is a type mismatch) in which case the legend is displayed in a floating element in bottom righ corner of the map. This is required when ``settings.gis.layer_metadata = True``.

settings.gis.location_represent_address_only [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables (resp. disables) showing latitude and longitude in *Location Represents*. The value can be also set to string ``"icon"`` (Note: This is a type mismatch).
| **Problem:** It's not clear how this value is intended to be used as it comes into consideration only when the class *gis_LocationRepresent* defined in file *modules/s3db/gis.py* on line 5821 is instantiated without explicitly setting either *sep* or *address_only* parameters. Such situation exists only in file *controllers/vulnerability.py*. In all other files and modules these conditions are not met.

settings.gis.mouse_position [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"normal"``
| **Description:** Sets display mode for map coordinates. Value ``"normal"`` shows latitude and longiture in degrees. Value ``"mgrs"`` show additionally a MGRS coordinate (Military Grid Reference System, see https://en.wikipedia.org/wiki/Military_Grid_Reference_System). Value ``None`` hides both.
| **Problem**: MGRS displays ``undefined`` in 100 km precision level coordinate for negative latitudes (below equator) and also displays ``undefined`` as full coordinate for latitudes above 80 and below -80 (around the poles).

settings.gis.nav_controls [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays map controls for *Zoom Out*, *Zoom In*, *Pan Map*, *Previous View* and *Next View* as buttons in map toolbar.

settings.gis.overview [O]
^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays an overview minimap. The minimap can be expanded using + (plus) icon in bottom right corner of the map.

settings.gis.permalink [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays a *Permalink* link in bottom right corner of the map which links to current zoom level, position and layer settings.

settings.gis.poi_create_resources [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List of dictionaries {string:string}
| **Default:**

.. code-block:: python

    [{"c": "gis",               # Controller
      "f": "poi",               # Function
      "table": "gis_poi",       # For permissions check
      # "type": "point",          # Feature Type: point, line or polygon
      "label": T("Add PoI"),    # Label
      # "tooltip": T("Add PoI"),  # Tooltip
      "layer": "PoIs",          # Layer Name to refresh
      "location": "button",     # Location to access from
    }]

| **Description:** Sets list of resources which can be added directly in the map window using a popup. See the dictionary keys and their meaning in the default value above. The resources need to have predefined dependencies (eg. *Type* for *PoI* or *Event* for *Incident Report*).
| **Problem:** While the advertised functionality works, it is suboptimal from UI/UX perspective as the popup windows move with the map and the map window clips them. Some forms also don't populate the *Latitude* and *Longitude* fileds using the data from the mouse click and display their own map in the popup instead.

settings.gis.poi_export_resources [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (string)
| **Default:** ``["cr_shelter", "hms_hospital", "org_office"]``
| **Description:** Sets list of resources (table names) for which to enable import/export in KML & OpenStreetMap formats as PoIs (eg. in *Import from OpenStreetMap* under *Locations*).
| **TODO:** Test imports.

settings.gis.print_button [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables map printing and displays corresponding *Take a screenshot of the map which can be printed* button in map taskbar. Requires python module *Selenium* and custom-compiled version of browser *PhantomJS* installed. See http://eden.sahanafoundation.org/wiki/UserGuidelines/Admin/MapPrinting and http://eden.sahanafoundation.org/wiki/InstallationGuidelines/PhantomJS for more details.
| **Problem:** There are multiple problems. First and foremost, the *PhantomJS* browser needs to be **custom-compiled** using version 2.1 (relased 2016-01-24) and cherry-picked commit https://github.com/ariya/phantomjs/commit/d0388371cfda166d97165c1b68182857b954cc83 to prevent cookie injection error.

.. code-block:: text

    "errorMessage":"Can only set Cookies for the current domain"

| Custom compilation adds nontrivial complexity and overhead to the whole support and maintenance cycle. Apart from the requirements listed in the link above, compilation also requires OpenSSL development files in version 1.0 () Additionally, an environment variable

.. code-block:: bash

    QT_QPA_PLATFORM=offscreen

| may need to be supplied to *Web2py* framework or *uwsgi* (depending on preferred launch method) on headless systems in order to avoid *Qt framework* error

.. code-block:: text

    QXcbConnection: Could not connect to display
    PhantomJS has crashed.

| When the *Selenium* and *PhantomJS* components are installed as required and the printing toolchain works, the generated map screenshots are anyway impractical. Either the map tiles don't load fast enough resulting in empty pink squares or there are additional modules enabled which leave menu items and other controls visible on the screenshot. Additionally, only the very first print request is completed successfully. All subsequent requests will time out with no result and keep timing out until *Sahana Eden* is restarted.

settings.gis.config_screenshot [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Tuple (integer, length = 2)
| **Default:** None
| **Description:** Sets dimensions of a screenshot for a map profile. The screenshot is created when a map admin clicks on *Save* button in the map toolbar. The value is expected in format ``(width, height)``.
| **Problem:** While the screenshot is correctly generated on the first click on *Save* button, all problems described for ``settings.gis.print_button`` apply also here. Moreover, subsequent clicks on the *Save* button also freeze client's web browser. The screenshot file is saved to location *static/cache/jpg/config_1.jpg* whereas in the web interface, Sahana Eden tries to load it from URL *default/download/config_1.jpg* which is not mapped to the saved resource, leading to error 404 - Not Found.

settings.gis.save [O]
^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays a *Save* button in map toolbar. The value can also be set to ``"float"`` (Note: This is a type mismatch) in which case the button is displayed in floating box in the upper right corner of the map.

settings.gis.scaleline [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays a scaleline in bottom right corner of the map.

settings.gis.search_geonames [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Search location in Geonames* input box in map toolbar. Requires ``settings.gis.geonames_username`` to be set.

settings.gis.simplify_tolerance [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Float
| **Default:** ``0.01``
| **Description:** Sets the tolerance for simplification of polygons in database queries and results. Lower value means less simplification, which is suitable for higher-resolution local activities whereas higher value is suitable for global views. Value ``0`` disables the tolerance threshold. Requires ``settings.gis.spatialdb = True``.

settings.gis.precision [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``4``
| **Description:** Sets the number of decimal places to work with in database queries and results. Requires ``settings.gis.spatialdb = True``.

settings.gis.toolbar [O]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays a map toolbar.

settings.gis.widget_catalogue_layers [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays all layers which are enabled by default in currently used map profile also in map widgets on resource profile and summary pages (eg. *Requests* or *Shelters*). Otherwise the layers are visible only in *Map* and the widgets display just base layer. Note that this setting does not affect selection map widgets (eg. *Incident reports*).

settings.gis.widget_wms_browser [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays WMS layer browser enabled in currently used map profile also in map widgets on resource profile and summary pages (eg. *Requests* or *Shelters*). This setting requires *Web Map Service Browser* to be populated in map profile. Note that this setting does not affect selection map widgets (eg. *Incident reports*).
| **Problem:** It seems that there is no possibility to save enabled layers selection in WMS layer browser, therefore no WMS browser layers are enabled by default when displaying map widgets on summary pages.

settings.gis.zoomcontrol [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays *Zoom in* and *Zoom out* buttons in upper left corver of the map.

settings.gis.popup_location_link [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays map in popup window when clicking on location representation link (eg. in *Organisations* -> *Offices*). The default value ``False`` causes the map to open above the details which include the location representation link.

settings.gis.xml_wkt [O]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables exporting of WKT (Well-Known Text) values in XML exports. Note: If this option is enabled and the database contains detailed geospatial data, the exported XML files can become very large.

settings.gis.geonames_username [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** If ``settings.gis.search_geonames = True``, enables the *Search location in Geonames* input box in map toolbar. Simultaneously sets the username reported to then *GeoNames* geolocation service. Note: Creation of own account for the geolocation service is strongly encouraged, see http://www.geonames.org/export/web-services.html.

settings.gis.edit_Lx [!]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Allows non-MapAdmins to edit hierarchy locations.
| **Problem:** This configuration directive is not referenced anywhere (including *modules/s3cfg.py*) and therefore has no effect.

settings.gis.edit_GR [!]
^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** This configuration directive is referenced only in *modules/s3cfg.py* on line 1134 but nowhere else, therefore has no effect.

settings.gis.check_within_parent_boundaries [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables latitude and longitude boundaries check when creating a location with a parent.

settings.gis.postcode_selector [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** True
| **Description:** Enables *Postcode* field in location selectors (eg. *Offices*).

Messaging settings
------------------

settings.msg.parser [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"default"``
| **Description:** Sets the template directory from which to load *parser.py* file. This file contains handlers for external message sources (Twitter, RSS, email, SMS etc.) which then can be bound to respective channels on *Parser Connections* page.
| **TODO:** Test messaging.

settings.msg.require_international_phone_numbers [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables requirement for E.123 internation phone number format (eg. in staffs' *Person Details*).
| **Problem:** Although the requirement for internation phone number format is enforced in some forms, the format is not validated during registration.

settings.msg.basestation_code_unique [N/A]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables requirement for unique base station (cell tower) code.
| **TODO:** Not really sure what this is supposed to do. It does not seem to be used anywhere.

Authentication, authorization and accounting settings
-----------------------------------------------------

settings.security.archive_not_delete [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables marking of database records as inactive instead of deleting them completely.

settings.security.policy [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``1``
| **Description:** Sets the level of security context which should be applied.

- ``1`` - Simple (default): Global as Reader, Authenticated as Editor
- ``2`` - Editor role required for Update/Delete, unless record owned by session
- ``3`` - Apply Controller ACLs
- ``4`` - Apply both Controller & Function ACLs
- ``5`` - Apply Controller, Function & Table ACLs
- ``6`` - Apply Controller, Function, Table ACLs and Entity Realm
- ``7`` - Apply Controller, Function, Table ACLs and Entity Realm + Hierarchy
- ``8`` - Apply Controller, Function, Table ACLs, Entity Realm + Hierarchy and Delegations

| Note: With the default level ``1``, all information entered in Sahana Eden instance are publicly accessible, therefore this level is suitable only for demonstration purposes. To use controller ACLs, it must be specified for which controllers ACLs are to be used using ``restricted = True`` in module configuration. For more details, see http://eden.sahanafoundation.org/wiki/S3/S3AAA.

settings.security.strict_ownership [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Sets the ownership for records without owner. Value ``False`` means that any authenticated user is considered an owner.
| **Problem:** While the setting affects SQL queries generated by Sahana Eden, the advertised effect of ``settings.security.strict_ownership = False`` doesn't seem to be achieved as authenticated users don't the same options and possibilities for records without owner as they do for records owned by them.

settings.security.audit_read [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables auditing for record reads. Note: Every record listing creates an audit record, therefore additional performance and capacity considerations have to be made.

settings.security.audit_write [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables auditing for record writes.

settings.security.map [!]
^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables (resp. disables) access to map editing.
| **Problem:** The setting does not seem to have any effect on map editing. Moreover it does not apply to *MapAdmin* role.

User interface settings
-----------------------

settings.ui.autocomplete_delay [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``800``
| **Description:** Sets the time in milliseconds for autocomplete dropdown display.

settings.ui.autocomplete_min_chars [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``2``
| **Description:** Sets the miniman amount of characters to trigget autocomple dropdown display.

settings.ui.filter_auto_submit [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``800``
| **Description:** Sets the time in milliseconds to automatically update filter targets after last filter option change.

settings.ui.report_auto_submit [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** ``800``
| **Description:** Sets the time in milliseconds to automatically update report filter targets after last filter option change.

settings.ui.cluster [O]
^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Sets the label to *Clusters* instead of *Sectors* (eg. in *Organisations* menu).

settings.ui.camp [+]
^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Sets the label to *Camp* instead of *Shelter*. Requires manual replacement in some places, eg. in the *Shelters* module definition.

settings.ui.iframe_opens_full [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables opening links from iframes in a new tab.
| **Problem:** While the setting seems to have effect where applicable, most of the links are hardcoded to open in new tab or popup anyway.

settings.ui.label_attachments [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Attachments"``
| **Description:** Sets the label of *Attachments* tab (eg. in *Offices* or *Facilities*).

settings.label_locationselector_map_point_add [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Place on Map"``
| **Description:** Sets label for *Place on Map* link.

settings.label_locationselector_map_point_view [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"View on Map"``
| **Description:** Sets label for *View on Map* link.

settings.ui.label_mobile_phone [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Mobile Phone"``
| **Description:** Sets label for *Mobile Phone* input field.

settings.ui.label_postcode [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Postcode"``
| **Description:** Sets label for *Postcode* input field.

settings.ui.social_buttons [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays social media share buttons linking to the current page. Generates links for *LinkedIn*, *Twitter* and *Facebook*.

settings.ui.hide_report_options [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Displays (resp. hides) *Report Options* on report pages. If this directive is set to the default value ``True``, the options can still be expanded by clicking on *Show* button in the *Report Options* form header.

settings.ui.auth_user_represent [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"email"``
| **Description:** Sets the user field to display as record owner. Possible values are ``"email"`` and ``"name"``.

settings.ui.datatables_dom [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"fril<'dataTable_table't>pi"``
| **Description:** Sets the page layout for data tables, including the filter, table and pagination. For more details see https://datatables.net/reference/option/dom.

settings.ui.datatables_initComplete [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Sets the JavaScript function (callback) to call after data tables receive data via AJAX, but before they are displayed.

settings.ui.datatables_pagingType [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"full_numbers"``
| **Description:** Sets the data table paging style. Possible values are ``"full_numbers"`` and ``"bootstrap"``.

settings.ui.export_formats [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (string)
| **Default:** ``("cap", "have", "kml", "map", "pdf", "rss", "xls", "xml")``
| **Description:** Sets list of allowed data export formats where applicable.

settings.ui.filter_clear [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``True`` (Note: This is a type mismatch)
| **Description:** Enables the button for clearing filter criteria and sets its label. Value ``True`` sets the detault label *Clear Filter*.

settings.ui.interim_save [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays *Save and continue editing* button in forms. This button serves the same purpose as the *Save* button, except it does not redirect to the read view.

settings.ui.use_button_icons [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:**  Displays additional icons on action buttons (*Open*, *Create*, *Delete* etc.). In data tables, replaces the action button labels with an icon.

settings.ui.multiselect_widget [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Replaces browser-native dropdown selects with customized selection widgets which support search.
| **Problem:** The customized selection widgets are supported only on registration page.

settings.ui.hierarchy_theme [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Dictionary {string:various}
| **Default:** ``{"stripes": True, "css": "plugins", "icons": False}``
| **Description:** Sets theme (style) for hierarchy selection widget. The key ``"css"`` represents a folder relative to *static/styles*
| **Problem:** Although the configuration directive is referenced in several modules, it doesn't seem that ``S3HierarchyWidget`` is rendered using this setting. This setting is supposed to be used eg. in *Create Need Type* in *Disaster Victim Registry* module while ``settings.dvr.needs_hierarchical = True``.

settings.ui.default_cancel_button [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays a *Cancel* button in forms which discards the form data and redirects to previous page.

settings.ui.datatables_responsive [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Adds a ``"responsive"`` CSS class to data tables. Usage of the class is up to the stylesheet designer. The default stylesheet makes no difference whether this class (resp. configuration directive) is used.

settings.ui.label_permalink [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"Link to this result"``
| **Description:** Changes the label for *Link to this result* link in filter.

settings.ui.menu_logo [O]
^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``URL(c = "static", f = "img", args = ["S3menu_logo.png"])`` (Note: function ``URL`` is defined in *Web2py* framework, file *gluon/html.py* on line 158)

| **Description:** Sets the path to logo displayed in upper left corner of *Sahana Eden* menu.

Asset settings
--------------

settings.asset.telephones [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Adds option ``"Telephone"`` to asset types in *Assets* module.

CMS settings
------------

settings.cms.hide_index [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Shows (resp. hides) CMS index page. The *Content Management* menu link then leads directly to CMS post listing.

settings.cms.bookmarks [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables usage of bookmarks in newsfeed.
| **Problem:** Although the option to filter bookmarks shows up after enabling this directive, there seems to be no control which could add a post in newsfeed into bookmarks.

settings.cms.filter_open [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Displays filter parameters in newsfeed as expanded. The default value ``False`` means that the filter is hidden and expanded only after clicking on *More Options*

settings.cms.location_click_filters [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** When set to ``True``, location link in newsfeed post adjusts the newsfeed filter to filter for the same location. The default value ``False`` causes the location link to redirect to location profile page.
| **Problem:** No filter adjustments happen when set to ``True``.

settings.cms.richtext [!]
^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables rich text editor for newsfeed.
| **Problem:** Although this directive is referenced in file *modules/s3db/cms.py* on line 221, the settings does not seem to have any effect as the texbox still allows only plaintext editing.

settings.cms.show_events [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables linking and display of events in newsfeed posts.

settings.cms.show_attachments [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables display of attachments in newsfeed posts. The attachments show as small paperclip icon in bottom right corner of the post.

settings.cms.show_links [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables creation and display of external links in newsfeed posts.

settings.cms.show_tags [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables creation and display of tags in newsfeed posts. The tags can be used for filtering.

settings.cms.show_titles [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables display of post title in newsfeed posts.

settings.cms.organisation [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"created_by$organisation_id"``
| **Description:** Enables linking and display of organisation in newsfeed posts. The value is a table column key, can be eg. ``"post_organisation.organisation_id"``.

settings.cms.organisation_group [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Enables linking and display of organisation group in newsfeed posts. The value is a table column key, can be eg. ``"post_organisation_group.group_id"``.

settings.cms.person [!]
^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``"created_by"``
| **Description:** Enables to manually enter information about newsfeed post owner instead of automatically filling the current user. The value is a table column key, can be eg. ``"person_id"``.
| **Problem:** Although the editation fields are displayed in newsfeed post form, they are greyed out and no other user can be selected.

Shelters settings
-----------------

settings.cr.shelter_population_dynamic [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables dynamic population estimation based on registrations. This setting is relevant only if ``settings.cr.people_registration = True``.

settings.cr.people_registration [O]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``True``
| **Description:** Enables tracking individuals in shelters via *Client Registration* tabs.

settings.cr.tags [O]
^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Enables tagging shelters via *Tags* tab.

settings.cr.shelter_inspection_tasks [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Allows generating tasks from shelter inspection Requires project module.
| **Project:** The inspection method is not accessible from the module menu and requires module customization. See *DRK* template for more details.

settings.cr.shelter_inspection_task_active_statuses [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** List (integer)
| **Default:** ``(1, 2, 3, 4, 5, 6, 11)``
| **Description:** Sets the list of active statuses of shelter inspection tasks. The values are are the same as in project tasks statuses.
| **Problem:** The inspection method is not accessible from the module menu and requires module customization. See *DRK* template for more details.

Disaster Victim Registry settings
---------------------------------

settings.dvr.label [O]
^^^^^^^^^^^^^^^^^^^^^^
| **Type:** String
| **Default:** ``None``
| **Description:** Switches the mode of *Disaster Victim Registry* between *Cases* and *Beneficiaries*. The only recognised value is ``"Beneficiary"``. The value is handled as boolean in most places in *modules/s3db/dvr.py* (Note: this is a type mismatch).

settings.dvr.multiple_case_groups [!]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Boolean
| **Default:** ``False``
| **Description:** Allows cases to belong to multiple case groups (*households*)
| **Problem:** Although the directive suggests it sets a value for *DVR* module, it actually sets a value for *Projects*. Moreover the modules require customization which does not seem to be present in any existing template.

Other
-----

settings.org.site_code_len [+]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| **Type:** Integer
| **Default:** 10
| **Description:** Sets the maximal length of *Site* code. Note that this affects only validation phase, the database filed is hard limited to 10 characters, therefore setting value >10 without adjusting the table definition leads to errors.

Additional notes
----------------

Registration to organisation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The registration via registration form suggests that the new user will be added to selected organisation and site if ``settings.auth.registration_requests_organisation`` and ``settings.auth.registration_requests_site`` are set appropriately. This is true from administration perspective, however the newly registered user does not automatically show up as *Staff* or *Volunteer*. Such option needs to be selected via ``settings.auth.registration_link_user_to`` options during user registration. If this is not done, it's not possible to use the same controls on already registered user (even though they are available) and the membership has to be added manually.

Realms
^^^^^^
By default, any organisation record (i.e. regardless whether root organisation or branch) is in its own realm. That means, only users who have a role for that organisation's realm can access the organisation record. When using hierarchical realms, branch organisations are /also/ in the realm their parent organisation. That means, users who have a role for the parent organisation can /also/ access the organisation records of all branches of that organisation.

Source: https://github.com/sahana/eden/pull/876#issuecomment-53703115

Type mismatches
^^^^^^^^^^^^^^^
Even though python is a weakly typed language, it's still a good practice to use types strictly and avoid unexpected behaviour by keeping single data type troughout the whole lifetime of a variable. Sahana Eden often uses ``False`` for undefined non-boolean values instead of ``None``, or uses a string instead a collection with a single element in configuration directives where collection is preferred. There are also several cases where seemingly boolean value has third state represented by string (see eg. ``settings.gis.legend``). Since the type sanity is not respected, few pointers on documented data type behaviour are included below.

Truth value testing
"""""""""""""""""""
Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered false:

- ``None``
- ``False``
- Zero of any numeric type, eg. ``0``, ``0L``, ``0.0``, ``0j``.
- Any empty collection, eg. ``''``, ``()``, ``[]``, ``{}``.
- Instances of user-defined classes, if the class defines a ``__nonzero__()`` or ``__len__()`` method, when that method returns the integer ``0`` (zero) or bool value ``False``.

All other values are considered true.

Comparisons
"""""""""""
========= =======
Operation Meaning
========= =======
\==        equal
!=        not equal
is        object identity
is not    negated object identity
========= =======

Objects of different types, except different numeric types and different string types, never compare equal. Object identity is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same value. Identity comparison can be expressed as ``id(a) == id(b)``. Note that integers in range from ``-5`` to ``256`` are considered literals.

Sources:

- https://docs.python.org/2.7/library/stdtypes.html
- https://docs.python.org/2/c-api/int.html

Accessibility and usability
^^^^^^^^^^^^^^^^^^^^^^^^^^^
*Sahana Eden* makes a heavy use of obtrusive JavaScript. While it is understandable that the JavaScript is needed for map functions, there are other components rendered solely using JavaScript and AJAX (eg. data tables) which makes the application unusable without JavaScript enabled. Moreover, almost no controls define ARIA properties.

Sources:

- https://en.wikipedia.org/wiki/Unobtrusive_JavaScript
- https://www.w3.org/WAI/intro/aria

3rd party API obsolescence
^^^^^^^^^^^^^^^^^^^^^^^^^^
*Sahana Eden* uses various API and web service calls to interface with 3rd party services. Considerable amount of these are obsolete or deprecated.

- Twitter REST API v1.0 used in newsfeed.
- RSSItForMe API which was supposed to replace Twitter REST API.
- Google Maps API v3.0 used in maps and geocoding. Note: *Sahana Eden* specifically queries for ``"v=3.0"`` minor version and not for latest release version using ``"v=3"``.
- OpenGEO WMS API used in map configuration supplied by default.
- TelaScience WMS API used in map configuration supplied by default.
- nowCOAST NOAA API used in map configuration supplied by default.
- EOSDIS NASA API used in map configuration supplied by default.
