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:
- jQuery DOM manipulation
- 20c-core class managment / inheritance / data loading
- 20c-edit wiring of forms to REST API, seamless switching between view and editor
- 20c-list-util list filtering and sorting
- autocomplete-light autocomplete fields
- dom-purify santize DOM
- showdown markdown to html
- js-cookie cookie utils
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 tostring
- reference to possible values belowreadonly
(bool
): ifTrue
property is not editablehelp_text
(str
): tooltip textadmin
(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 flagsvalue
(list<dict>
): one entry for each checkbox (flag), each item should be adict
containingname
andvalue
keys (required)
url
list
data
(str
): data loader name (required) - reference to data loaders belowmultiple
(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 UXgroup
: 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 isupdate
ordelete
)payload
(list<dict>
): can specify extra payload to send with the API write call, each item should be adict
containingname
andvalue
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.