Metadata-Version: 2.4
Name: splent_feature_orcid
Version: 0.1.0
License-Expression: LGPL-3.0-or-later
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: COPYING
License-File: COPYING.LESSER
Dynamic: license-file

# splent_feature_orcid

The `orcid` feature of a [SPLENT](https://splent.io) product line.

Sign in and sign up with ORCID, and connect an ORCID iD to an account from
its profile. A new account asks for an email address first, since ORCID
rarely shares one, and is filled with the name ORCID gives. An ORCID iD
always signs in to the account it is linked to, and never to an existing
account because the typed email matches. It needs `auth`, `profile` and
`identities`, which keeps the linked accounts and the shared OAuth registry.

A SPLENT feature is a Python package that a product composes with others.
Its models, routes, services, templates and hooks are registered when the
product starts. What this feature provides and requires is listed in the
`[tool.splent.contract]` section of `pyproject.toml`, which
`splent feature:contract --write` keeps in sync with the source.

## Settings

| Setting | Default | What it is |
|---|---|---|
| `ORCID_CLIENT_ID` | empty | The client id of the application registered at https://orcid.org/developer-tools |
| `ORCID_CLIENT_SECRET` | empty | Its secret |

Without both, ORCID sign-in fails with a message and the app logs a warning
at startup.

## Where it shows

It fills the slots other features open, by name, so it composes with
whatever the product has and overrides nothing.

| Slot | Opened by | What ORCID draws |
|---|---|---|
| `auth.login.providers` | auth | The ORCID button, under "or continue with" |
| `signup.providers` | signup, when the product has it | The same button, after the sign-up form |
| `profile.edit.sections` | profile | The linked iD with a disconnect button, or a "Connect ORCID" link |
| `layout.scripts` | the product's layout | The connect-with-email modal, on the edit-profile page only |
| `layout.head.css` | the product's app shell | Its stylesheet, `assets/css/orcid.css` |

It takes order 20 in the first three, after GitHub's 10. The button carries
where the reader was heading (`?next=`), and only a path on this site.

ORCID's green is in `assets/css/orcid.css`, never on the elements. The public
shell loads the file from the asset registry (`register_asset`), and the app
shell, which does not render the registry, through `layout.head.css`. A
product that wants another look overrides `.btn.btn-orcid` and the
`orcid-identity__*` classes in a stylesheet of its own.

## A product without signup

A product that does not install `splent_feature_signup` is closed, and its
accounts are opened by an administrator. ORCID follows the rule identities
holds for every provider.

| Visitor | With signup | Without signup |
|---|---|---|
| Signs in with an ORCID iD already linked | Signed in | Signed in |
| Connects ORCID from their profile | Linked | Linked |
| Signs in with an ORCID iD linked to nobody | Asked for an email, then a new account is opened | Sent back to the login page with a translated message that asks them to request access from an administrator, or to connect ORCID from their profile if they have an account |

Without signup the ORCID button goes straight to ORCID, since the email step
only serves a new account.

## What it adds to the profile

| What | How | Needs |
|---|---|---|
| `get_orcid()` on profile's `UserProfile`, the linked iD or `None`, which dataset authors and the API read | A refinement declared in `pyproject.toml` (`[tool.splent.refinement]`), applied by the framework when the product starts | profile |
| The `orcid` key of `/api/v1/profile/me`, the linked iD or `null` | profile's `register_profile_payload` | profile |
| The affiliation of an account created through ORCID, when ORCID sends one | Written when the profile has an `affiliation` column, read from profile's `profile_columns()` | academic_profile, or any feature that adds the column |

```json
{"name": "Ada", "surname": "Lovelace", "email": "ada@example.com", "orcid": "0000-0002-1825-0097"}
```

Without academic_profile the affiliation is not kept and the account is
created all the same.

`get_orcid()` is a method and adds no column. It sits beside the other
refiners of `UserProfile`, such as academic_profile, which adds
`affiliation` to the same model, so a product can have both.

`register_profile_payload` and `profile_columns` are new in the profile
released with this version. Against an older profile ORCID still starts.
It reads the columns from the `UserProfile` table instead, and leaves the
`orcid` key out with a warning in the log. An older profile's edit page
also opens no `profile.edit.sections` slot, so it shows no ORCID row, and
the iD cannot be connected or disconnected from the profile. Signing in
with ORCID works as usual. Only a missing module or function counts as an
older profile. An error inside profile's own code stops the start as it
is, rather than passing for one.

## Translations

The edit-profile row ships with a Spanish catalog.

## Use it in a product

```bash
splent feature:add splent_feature_orcid
```

## Develop

```bash
splent feature:test splent_feature_orcid
splent feature:contract splent_feature_orcid
```

## Release

```bash
splent feature:release splent_feature_orcid --dry-run --bump patch
splent feature:release splent_feature_orcid
```

The first command rehearses the release and changes nothing. The second
publishes it to the git forge and to PyPI, and a PyPI version is permanent.
