1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00
Files
peeringdb-peeringdb/docs/dev/views.md
Matt Griswold 1eda45ffeb ignore new ixf field (#1082)
* ignore new ixf field

* pre-commit

* gh actions linting fix
2021-10-30 10:20:04 -05:00

6.3 KiB

Django views

Most django views that make up the UX for PeeringDB are located in views.py

Templates for these views can be found in templates/site

Javascript

PeeringDB uses the following third party js libraries:

These libraries are to be found in the /static directory

PeeringDB specific javascript code can be found in these files:

  • /static/peeringdb.js: main javascript code
    • REST API client
    • advanced search
    • custom 20c-edit input types
    • custom 20c-edit editor handlers
    • data loaders
    • ix-f post mortem, preview and review tools
    • quick search
    • api key permissions
    • user permissions
    • org user editor
  • /static/peeringdb.admin.js: django-admin aditions
    • org merge tool

Entity views

In order to render the org, net, fac and ix views a single template is used.

That template exists at templates/site/view.html

Properties are passed through to this templates from their respective views in views.py

  • views.py::view_network
  • views.py::view_facility
  • views.py::view_exchange
  • views.py::view_organization

Data is built by using the REST api serializers

We use the REST API data serialization to build the data piped into those entity views.

data = InternetExchangeSerializer(exchange, context={"user": request.user}).data

This allows us to make use of the permissioning of sensitive data according to the user's viewing permissions that already exists within the REST API functionality.

Data is passed through to the template in field definitions using a dict for each field.

These field definitions get turned into UI elements that provide both a normal view rendering of the property as well as an edit-mode form field.

On the frontend, this UX behavior is handled by the 20c-edit library.

Entity field definitions

Each field definition has the following common properties:

  • name (str): the name of the field as it exists in the REST API (required)
  • label (str): the label of the field as it is shown in the UX (required, i18n)
  • value (mixed): the value (required)
  • type (str): field type - defaults to string - reference to possible values below
  • readonly (bool): if True property is not editable
  • help_text (str): tooltip text
  • admin (bool): only visible to object administrators

Some types have specific properties, find those listed below:

Field types

  • string (default)
  • number
  • flags: renders checkboxes for boolean flags
    • value (list<dict>): one entry for each checkbox (flag), each item should be a dict containing name and value keys (required)
  • url
  • list
    • data (str): data loader name (required) - reference to data loaders below
    • multiple (bool): allow multi select
  • email
  • entity_link: link to another peeringdb object (org for example)
    • link (str): relative url path (required)
  • sub: starts a new sub section in the UX
  • group: starts a new group of form elements that will target a separate API endpoint.
    • target (str): api target for these form elements in the format of "api:{reftag}:{update|create|delete}" (required)
    • id (int): api target id (object id) (required if target is update or delete)
    • payload (list<dict>): can specify extra payload to send with the API write call, each item should be a dict containing name and value keys

Data Loaders for list elements

<select> elements will be created for list type fields. In order to fill these elements with data, PeeringDB employs asynchronous data loaders.

Data loaders need to be setup across several files before they become usable.

data_views.py

The view that provides the actual data

def my_organizations(request):
    """
    Returns a JSON response with a list of organization names and ids
    that the requesting user is a member of
    """
    if not request.user.is_authenticated:
        return JsonResponse({"my_organizations": []})

    return JsonResponse(
        {
            "my_organizations": [
                {"id": o.id, "name": o.name} for o in request.user.organizations
            ]
        }
    )

Note: The JSONResponse needs to provide the data keyed to a name that is identical to the loader name; therefore the value of "my_organizations" in the response is NOT arbitrary.

urls.py

URL routing needs to be set up:

    url(r"^data/my_organizations$", peeringdb_server.data_views.my_organizations),

static/peeringdb.js

The front-end needs to assign the loader:

twentyc.data.loaders.assign("my_organizations", "data");

Field permissioning

Because the REST API serializers are used to build the field definitions and values sent to the views, some fields may be omitted due to missing permissions.

To avoid this issue, the value passed should always provide a reference to dismiss as a default:

        "value": data.get("country", dismiss),

The dismiss object will hide the field if it was not provided in the data.

Manual permissioning of fields

In instances where you want to check permissions after the data has been serialized, you can do so using the DoNotRender object:

        "value": DoNotRender.permissioned(
            # value
            ixlan.ixf_ixp_member_list_url,
            # user
            request.user,
            # permissioning name-space
            f"{ixlan.grainy_namespace}.ixf_ixp_member_list_url.{ixlan.ixf_ixp_member_list_url_visible}",
            # require explicit permissions to the namespace for the field to be viewable
            explicit=True,
        ),

PeeringDB uses django-grainy for granular permission checking and handling.