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

# splent_feature_projects

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

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.

## What it does

Projects, active and past. `/projects` lists the published projects grouped
by status, and `/projects/<slug>` shows one of them. A project that is not
published stays out of the list, and its page answers 404 to everyone but
the panel's accounts, who see it with a notice that it is a draft. The
description is stored HTML, and the page draws it through the framework's
`rich_text` filter, which keeps the formatting and drops scripts, event
handlers and `javascript:` links.

The panel manages the projects at `/admin/projects`, where they are added,
edited, moved to another group and deleted. The admin form follows the
columns of the `Project` model, so the fields a refinement adds to it (an
acronym, a funding agency, dates) are saved with no change here.

## Addresses

A project's link goes into an `href` and its image into a `src`, so the
form checks them with the framework's `is_safe_url` before storing them.
An `http://`, `https://` or `mailto:` address and a path on the site such
as `/static/uploads/project.png` are stored. Any other scheme,
`javascript:` and `data:` among them, is refused with a message, nothing
is saved, and the form comes back with what was typed. A refinement that
overrides `projects/admin/form.html` shows `submitted`, what was typed,
when it is given, and `project` otherwise.

The pages draw every stored address through the `safe_url` filter, so one
a seeder or an import wrote without the check renders as an empty `href`
or `src` instead of running.

## Access

The screens under `/admin/projects` open for the accounts whose role is
`admin` or `staff`, the same pair the admin dashboard lets in. Any other
signed-in account gets 403 and does not see the Projects link in the
sidebar, and an anonymous visitor is sent to log in.

The published list and detail pages stay open to everyone, signed in or
not. The page of a draft at `/projects/<slug>` opens only to the accounts
the admin screens let in, so they can check it before publishing, with a
notice that the public cannot see it. Everyone else gets 404, as for a
project that does not exist. The notice is a flashed message that the page
layout shows, so it stays when a refinement overrides the detail template.

There is no setting for these roles, and a refinement cannot replace the
views that check them, because it may add routes to this feature but never
replace one of its own. Another feature can decide for these screens with an
access policy registered for the prefix `projects.admin`
(`register_access_policy`, splent_framework 1.20.0). The framework asks the
policy before the roles. It answers True to let an account in, False to
refuse it, or None to leave the decision to the roles, and the sidebar link
and the preview of a draft follow the same answer. For the preview the
policy is asked about `projects.admin_index` with the draft's slug as
`view_args`, `{"slug": "<slug>"}`, so it can let an account preview some
drafts and not others. That is the way to let a group of accounts manage
only this section, for example the members who keep the projects up to
date, without giving them a panel role.
See [Access control](https://docs.splent.io/framework/access-control).

Without such a feature, give the person's account the staff role. Staff
opens every panel screen that asks for `PANEL_ROLES`, not only this one, so
a person who should manage nothing but the projects needs a policy instead.

```bash
splent feature:auth set-role someone@example.com staff
```

## Use it in a product

```bash
splent feature:add splent_feature_projects
```

## Develop

```bash
splent feature:test splent_feature_projects
splent feature:contract splent_feature_projects
```

## Release

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

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.
