Skip to main content
Ctrl+K
fairdm 0.3.1 documentation - Home fairdm 0.3.1 documentation - Home
    • Developers
    • Administrators
    • Users
    • What FairDM is for
    • FAIR data and research data infrastructure
    • The technology stack
    • The core data model
    • How sample and measurement types are stored
    • Controlled vocabularies
    • Configuration over code
    • Why complete metadata matters
    • How access to a record is decided
    • Why FairDM records contributors
    • How contributor accounts and credits work
    • How a profile is claimed
    • How FairDM configures a portal
    • Who is asked to agree to a legal document
    • How locations are stored and protected
    • Dataset publication, DOIs and DataCite metadata
    • Glossary
    • Framework Contributors
    • Architecture Decision Records
    • Roadmap — FairDM
    • Changelog
  • GitHub
  • GitHub
  • Developers
  • Administrators
  • Users
  • What FairDM is for
  • FAIR data and research data infrastructure
  • The technology stack
  • The core data model
  • How sample and measurement types are stored
  • Controlled vocabularies
  • Configuration over code
  • Why complete metadata matters
  • How access to a record is decided
  • Why FairDM records contributors
  • How contributor accounts and credits work
  • How a profile is claimed
  • How FairDM configures a portal
  • Who is asked to agree to a legal document
  • How locations are stored and protected
  • Dataset publication, DOIs and DataCite metadata
  • Glossary
  • Framework Contributors
  • Architecture Decision Records
  • Roadmap — FairDM
  • Changelog
  • GitHub
  • GitHub

Section Navigation

Tutorial

  • Build your first sample and measurement types

How-to guides

  • How to add a factory for a portal model
  • How to add a filter to a sample type
  • How to add a measurement type
  • How to add a record field to a form
  • How to add a sample type
  • How to add a section to the home page
  • How to add a start step to a container
  • How to add a transform for another format
  • How to add a viewset to the API router
  • How to add an entry to the Manage menu
  • How to add an environment override module
  • How to add pages to a plugin
  • How to add queryset methods to a measurement type
  • How to add search and sort to a list view
  • How to allow only some sites to call the API
  • How to back up a portal
  • How to change a type’s API address
  • How to change how the team page looks
  • How to change the API rate limits
  • How to change the entrance layout
  • How to change the entrance pane
  • How to change the portal theme
  • How to change what a home page section shows
  • How to change what the edit details page offers
  • How to choose the fields the API returns
  • How to configure the agreement check
  • How to count API callers behind a proxy
  • How to create a ghost person
  • How to create a plugin
  • How to create an addon
  • How to credit a person on a record
  • How to customise a generated component
  • How to customise a sample form
  • How to customise the admin for a measurement type
  • How to customise the API documentation
  • How to customise the profile form
  • How to define a portal role of your own
  • How to deploy a portal in a container
  • How to develop a portal on the development image
  • How to extend an overview page
  • How to extend the profile-claiming flow
  • How to filter a list by a record
  • How to filter projects by vocabulary keywords
  • How to find records by where they are
  • How to give a sample or measurement a location
  • How to give a sample or measurement type its own overview page
  • How to grant object permissions on a polymorphic model
  • How to import and export locations
  • How to import people from a list of ORCID iDs
  • How to link to a legal document
  • How to load development data for the overview pages
  • How to loop over the registered types
  • How to narrow a record field by another field
  • How to override a FairDM setting
  • How to place an organization on a map
  • How to record sample relationships
  • How to register a sample or measurement type
  • How to render markdown in a template
  • How to restore a portal from a backup
  • How to restrict a plugin to some users
  • How to restrict a record field to one sample type
  • How to restrict API tokens to some people
  • How to run a background worker in a container
  • How to search a registered type by more than its name
  • How to show part of a page to a record’s team
  • How to sign in as each portal role while developing
  • How to sync a profile from ORCID or ROR without Celery
  • How to test a portal with FairDM factories
  • How to upgrade a portal to django-literature 0.3
  • How to upgrade a portal to vocabulary addresses
  • How to use a controlled vocabulary in a model
  • How to use a sample form in a view
  • How to write a custom form or filter for a measurement type

Reference

  • Base views
  • Components
  • Configuration
  • Container images
  • Contribution levels and record access
  • Contributor models
  • Core models
  • Crediting
  • Development accounts
  • Entrance pages
  • Form and filter mixins
  • Home page
  • Legal documents
  • Location fields
  • Management commands
  • Measurement model
  • Model configuration
  • Model fields
  • Overview page blocks
  • Overview plugins
  • Plugins
  • Portal roles in code
  • Profile claiming
  • Record editing pages
  • Record fields
  • REST API
  • Sample model
  • Settings
  • Template tags
  • Test factories
  • The registry
  • Python API
    • fairdm
      • fairdm.db
        • fairdm.db.managers
        • fairdm.db.models
        • fairdm.db.fields
      • fairdm.contrib
        • fairdm.contrib.autocomplete
        • fairdm.contrib.admin
        • fairdm.contrib.collections
        • fairdm.contrib.plugins
        • fairdm.contrib.contributors
        • fairdm.contrib.location
        • fairdm.contrib.identity
        • fairdm.contrib.import_export
      • fairdm.conf
        • fairdm.conf.settings
        • fairdm.conf.checks
        • fairdm.conf.development
        • fairdm.conf.urls
        • fairdm.conf.celery
        • fairdm.conf.setup
        • fairdm.conf.addons
        • fairdm.conf.environment
      • fairdm.management
        • fairdm.management.commands
      • fairdm.templatetags
        • fairdm.templatetags.fairdm
      • fairdm.core
        • fairdm.core.project
        • fairdm.core.dataset
        • fairdm.core.measurement
        • fairdm.core.sample
        • fairdm.core.vocabularies
        • fairdm.core.formsets
        • fairdm.core.admin
        • fairdm.core.dates
        • fairdm.core.overview
        • fairdm.core.managers
        • fairdm.core.image_utils
        • fairdm.core.models
        • fairdm.core.utils
        • fairdm.core.urls
        • fairdm.core.permissions
        • fairdm.core.forms
        • fairdm.core.abstract
        • fairdm.core.choices
        • fairdm.core.filters
        • fairdm.core.plugins
        • fairdm.core.descriptions
        • fairdm.core.related_records
        • fairdm.core.apps
        • fairdm.core.editing
      • fairdm.forms
        • fairdm.forms.base
        • fairdm.forms.fields
      • fairdm.factories
        • fairdm.factories.core
        • fairdm.factories.contributors
        • fairdm.factories.utils
      • fairdm.views
        • fairdm.views.base
        • fairdm.views.mixins
        • fairdm.views.generic
      • fairdm.api
        • fairdm.api.checks
        • fairdm.api.router
        • fairdm.api.urls
        • fairdm.api.permissions
        • fairdm.api.throttling
        • fairdm.api.viewsets
        • fairdm.api.filters
        • fairdm.api.serializers
        • fairdm.api.pagination
        • fairdm.api.apps
        • fairdm.api.schema
        • fairdm.api.settings
      • fairdm.backups
        • fairdm.backups.management
        • fairdm.backups.media
        • fairdm.backups.tasks
        • fairdm.backups.run
        • fairdm.backups.keys
        • fairdm.backups.signals
        • fairdm.backups.apps
      • fairdm.registry
        • fairdm.registry.exceptions
        • fairdm.registry.config
        • fairdm.registry.factories
        • fairdm.registry.registry
      • fairdm.utils
        • fairdm.utils.location
        • fairdm.utils.markdown
        • fairdm.utils.inspection
        • fairdm.utils.models
        • fairdm.utils.utils
        • fairdm.utils.permissions
        • fairdm.utils.choices
        • fairdm.utils.context_processors
      • fairdm.config
      • fairdm.models
      • fairdm.portal_roles
      • fairdm.permissions
      • fairdm.menus
      • fairdm.plugins
      • fairdm.apps

Explanation

  • How a measurement reports its value
  • How API callers are limited
  • How FairDM views are layered
  • How markdown is sanitised
  • How record fields decide what to offer
  • How the container images are versioned
  • What registering a type produces
  • Why factories create metadata only when asked
  • Developers
  • Legal documents

Legal documents#

This page lists what a FairDM portal has for legal documents: the pages, the URL names, the permissions, the models you can query and the system checks. It does not describe the settings, which are in Settings, or who is asked to agree, which is in Who is asked to agree to a legal document.

FairDM installs django-mvp-compliance, the mvp_compliance app, and wires it in for every portal that calls fairdm.setup():

  • mvp_compliance is in INSTALLED_APPS.

  • mvp_compliance.middleware.AgreementMiddleware is in MIDDLEWARE.

  • fairdm.conf.urls mounts mvp_compliance.urls under legal/.

  • An Agreements entry is added to the account area’s menu.

FairDM ships no documents. Until your portal publishes one, there are no pages under /legal/ and the check asks nobody anything.

Pages and URL names#

URL name

Address

Who may open it

What it shows

mvp_compliance:document

/legal/<slug>/

Everyone

A document in the version in force. ?version=<number> shows any published version of it

mvp_compliance:agree

/legal/agree/

Signed-in people

The documents outstanding for the person, each with a toggle. Accepts a next address to go on to

mvp_compliance:agreed

/legal/agreed/

Signed-in people

The person’s own list of the versions they accepted

The document page answers “not found” for a slug that names no document, a document with nothing published and a ?version= value that names no published version. It answers the same way to a signed-in person as to a visitor.

The agreed page answers “not found” in a portal whose URL configuration has no account-center name.

The slugs agree and agreed are reserved and cannot name a document.

Documents and versions#

A document has a name, a slug and a kind. A version holds the text.

Field

Type

Default

What it does

Document.name

str, 100 characters

None

The name the document is known by. Unique

Document.slug

slug, 100 characters

None

The segment of the document’s address. Unique, lowercase. It cannot change once a version is published

Document.kind

"agreed" or "notice"

"agreed"

Whether people agree to the document or only read it. Nobody is asked to accept a notice

Document.enforced

bool

True

Whether a person who has not accepted the document is stopped until they do. It never applies to a notice

Version.markdown

text

None

The wording, in Markdown

Version.status

"draft", "current" or "superseded"

"draft"

Set by publishing. A document has at most one current version

Version.number

str

None

The year and the version’s place among that year’s versions, such as 2026.1. A draft has none

A published version can never be edited. A correction is a new version.

Creating a document from code#

from mvp_compliance.models import Document

terms = Document.objects.create(name="Terms of use", slug="terms-of-use")
terms.versions.create(markdown="# Terms of use\n\n...").publish()

Version.publish(publisher=None) makes a draft the version in force and supersedes the one that held it. It raises PublishError when the version is not a draft, when its rendered output is empty and when it says exactly what the version in force says.

Queries#

Method

Returns

Document.objects.in_force()

The documents that have a version in force

Document.objects.outstanding_for(user)

The documents whose version in force user has not accepted. A notice is never outstanding

Document.objects.enforced_outstanding_for(user)

The outstanding documents that are enforced

document.current

The version in force, or None

document.is_outstanding_for(user)

True when document is outstanding for user

Permissions#

All belong to the mvp_compliance app.

Permission

What it allows

add_document, change_document

Writing documents in the administration interface

add_version, change_version

Writing draft versions

publish_version

Publishing a version, which puts it in force at once

skip_agreement

Going on without accepting the enforced documents. Superusers are never stopped

None of the four portal roles holds these.

System checks#

The checks run only when AgreementMiddleware is in MIDDLEWARE.

ID

Severity

It reports

mvp_compliance.E001

Error

The page that asks has no address, because mvp_compliance.urls is not mounted

mvp_compliance.E002

Error

Nothing that identifies the signed-in user comes before AgreementMiddleware

mvp_compliance.E003

Error

MVP_COMPLIANCE_AGREEMENT_EXEMPT_URLS or MVP_COMPLIANCE_AGREEMENT_EXEMPT_USERS is a string where a list is needed

mvp_compliance.E004

Error

MVP_COMPLIANCE_AGREEMENT_CHECK_INTERVAL is not a number

Related pages#

  • Settings for every MVP_COMPLIANCE_* setting

  • How to link to a legal document

  • How to configure the agreement check

  • How to write and publish a legal document, for the person who writes the text

previous

Home page

next

Location fields

On this page
  • Pages and URL names
  • Documents and versions
    • Creating a document from code
    • Queries
  • Permissions
  • System checks
  • Related pages

© Copyright 2026, Samuel Jennings.

Built with the PyData Sphinx Theme 0.21.0.