No description
  • Python 97%
  • Makefile 3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Gilles Fritz e67c5a96d6
All checks were successful
ci / test (3.12) (push) Successful in 35s
ci / test (3.13) (push) Successful in 33s
ci / test (3.14) (push) Successful in 34s
ci / test (3.15) (push) Successful in 35s
ci / test (3.11) (push) Successful in 34s
ci / lint (push) Successful in 57s
ci / publish (push) Successful in 24s
Send publish reports to Argus from the release job (#8)
Closes #7

Monitoring plan, phase 5 rollout, same as the pilots argus/backend#45 and argus/frontend#35.

## Changes (`.forgejo/workflows/ci.yml`)
- New step "Collect publish details for Argus": `ARGUS_ARTIFACT` = built wheel `name|bytes|package page`; `/tmp/dependencies.txt` = the runtime dependencies declared in `pyproject.toml` (`name specifier` lines, e.g. `Django >=4.2`).
- Both publish-release calls (numbered release, devel snapshot) get `ARGUS_UPLOAD_TOKEN: ${{ secrets.ARGUS_UPLOAD_TOKEN }}` and `--artifact "$ARGUS_ARTIFACT" --dependencies /tmp/dependencies.txt`. A failed upload only warns, the release itself is unaffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_014BSmBtGWeFBD9z4mYm9SjA
Reviewed-on: #8
2026-10-30 08:13:01 +00:00
.forgejo/workflows Send publish reports to Argus from the release job (#8) 2026-10-30 08:13:01 +00:00
src/bigb QuerySpec: choose the returned fields (#6) 2026-10-29 22:00:35 +00:00
tests QuerySpec: choose the returned fields (#6) 2026-10-29 22:00:35 +00:00
.gitignore Migrate onto Argus for test/coverage reporting 2026-10-16 13:11:21 +02:00
.pylintrc Scaffold bigb-django: moteur de requêtes JSON, dashboards, permissions 2026-10-09 23:15:24 +02:00
COPYING Scaffold bigb-django: moteur de requêtes JSON, dashboards, permissions 2026-10-09 23:15:24 +02:00
COPYING.LESSER Scaffold bigb-django: moteur de requêtes JSON, dashboards, permissions 2026-10-09 23:15:24 +02:00
Makefile Scaffold bigb-django: moteur de requêtes JSON, dashboards, permissions 2026-10-09 23:15:24 +02:00
pyproject.toml ci: publish releases with ci-base's publish-release 2026-10-24 10:05:19 +02:00
README.md QuerySpec: choose the returned fields (#6) 2026-10-29 22:00:35 +00:00
renovate.json Scaffold bigb-django: moteur de requêtes JSON, dashboards, permissions 2026-10-09 23:15:24 +02:00
tox.ini Migrate onto Argus for test/coverage reporting 2026-10-16 13:11:21 +02:00

bigb-django

CI Coverage Tests License: LGPL v3

Configurable dashboards for Django: declarative JSON queries against a Django project's models (explicitly whitelisted, no implicit access), JSON or SVG rendering (via pygal), named saved queries, and grid dashboards shareable by user or group. The Vue 3 frontend counterpart is bigb-vue.

Installation

pip install bigb-django
# settings.py
INSTALLED_APPS = [
    ...,
    "django.contrib.auth",
    "bigb",
]

BIGB_MAX_LIMIT = 1000  # cap applied to `limit` in a QuerySpec
# urls.py
urlpatterns = [
    ...,
    path("bigb/", include("bigb.urls")),
]

Don't forget python manage.py migrate (SavedQuery, Dashboard, DashboardTile models).

Declaring queryable models

Nothing is queryable by default. Each app explicitly declares what it exposes, in a bigb_queries.py module (auto-discovered at startup, the same way admin.py is for the Django admin):

# myapp/bigb_queries.py
from bigb import registry
from .models import Order

registry.register(
    Order,
    fields=["id", "status", "amount", "created_at"],
    filterable=["status", "created_at"],
    aggregatable=["amount"],
    # Optional: called back on EVERY execution (not just when the query
    # is saved), so it protects already-saved queries too.
    scope=lambda qs, user: qs.filter(tenant=user.tenant),
)

QuerySpec (JSON)

{
  "model": "orders.Order",
  "filters": [{"field": "status", "op": "eq", "value": "paid"}],
  "group_by": ["status"],
  "aggregates": [{"func": "sum", "field": "amount", "as": "total"}],
  "order_by": ["-total"],
  "limit": 100
}
  • fields (optional, no group_by/aggregates): the columns returned, in that order -- e.g. ["created_at", "amount"] for a line chart. Absent: every registered field.
  • op: eq, neq, gt, gte, lt, lte, in, contains, isnull.
  • func: count, sum, avg, min, max. {"func": "count"} without field counts all rows (count_all).
  • Every field referenced must be in the model's whitelist in the registry (fields/filterable/aggregatable), otherwise a 400.

API

All routes require an authenticated session.

Method Route Description
POST /bigb/query/ Run an ad hoc QuerySpec (execute_query)
GET/POST /bigb/queries/ List / create a saved query
GET/PATCH/DELETE /bigb/queries/<slug>/ Detail / update / delete
GET /bigb/queries/<slug>/data/?format=json|svg&chart=line Result (view_savedquery_results)
GET/POST /bigb/dashboards/ List / create a dashboard
GET /bigb/dashboards/default/ The current user's default dashboard -- their own is_default one, or else the first is_default one shared with one of their groups. 404 if neither exists
GET/PATCH/DELETE /bigb/dashboards/<slug>/ Detail (with tiles) / update / delete
POST /bigb/dashboards/<slug>/tiles/ Add a tile
PATCH/DELETE /bigb/dashboards/<slug>/tiles/<id>/ Update / delete a tile
GET /bigb/dashboards/<slug>/tiles/<id>/data/?format=json|svg Tile result
GET /bigb/registry/ Available models/fields/aggregates

format=svg accepts chart=line\|bar\|pie, title=..., label_field=....

Permissions

Standard Django permissions, assignable per user or per group (so manageable from the Django admin). Each resource has a base permission, scoped to "my objects, or ones shared with my user/my groups" (shared_users/shared_groups), and an *_all permission that lifts that scoping:

Permission Effect
view_savedquery View queries you own or are a sharing recipient of
view_all_savedquery View everyone's queries
view_savedquery_results Run/view the data of an already-visible query
execute_query Run an ad hoc (unsaved) query
add_savedquery Create a query
change_savedquery / change_all_savedquery Edit your own queries / everyone's
delete_savedquery / delete_all_savedquery Delete your own queries / everyone's
view_dashboard / view_all_dashboard View your dashboards (+ shared) / everyone's
add_dashboard Create a dashboard
change_dashboard / change_all_dashboard Edit your own dashboards / everyone's
delete_dashboard / delete_all_dashboard Delete your own dashboards / everyone's
manage_group_dashboard Create a dashboard shared with a group, or change/delete one that already is -- a separate gate from change_dashboard/change_all_dashboard, which only ever lift the ownership scoping. Without it, sharing a dashboard with a group (or editing one someone else already shared with a group) is refused even for its own owner

A Dashboard.is_default flag marks the one to show automatically for its owner (or, for a group-shared dashboard, for members of that group who have no personal default of their own) -- see /bigb/dashboards/ default/ above. Setting it follows the same rules as any other field: no extra permission for your own dashboard, manage_group_dashboard for a group-shared one.

Per-query extra permission

SavedQuery.required_permission (blank by default) names one extra Django permission (app_label.codename) a viewer must additionally hold to see that specific query's results -- on top of, never instead of, the usual view_savedquery_results + shared_with check. Useful when a query is shared with a group but its data should stay reserved to whoever also holds some more specific permission (e.g. a host app scoping a sensitive aggregate to its own "staff" permission, while a blander one in the same dashboard stays open to the whole group). It only ever gates results: the query's own definition stays visible to anyone the normal view_savedquery/shared_with rules already let see it (so it can still be listed, just not run), and a blank value changes nothing, which is the default for every existing query. Settable via POST /bigb/queries//PATCH /bigb/queries/<slug>/ like any other field.

Development

make dev    # venv + editable install + [dev] extras
make test   # pytest
make lint   # pylint (pylint-django)
make format # autopep8 --in-place
make bandit # static security analysis
make tox    # every environment (py311-py315 + lint + format + bandit)