ipdate
Some checks failed
DevPlace CI / test (push) Failing after 1h9m6s

This commit is contained in:
retoor 2026-08-10 03:12:43 +02:00
parent f3b91ac75b
commit 782bcec5bc
5 changed files with 2 additions and 45 deletions

View File

@ -185,7 +185,7 @@ Online status is a single **`users.last_seen`** UTC-ISO column (ensured in `data
**Write path (all workers):** `main.py`'s `track_presence` HTTP middleware resolves the cached current user on every non-`/static`, non-`/avatar` request and calls `presence.touch(uid)`. `touch` keeps a per-worker in-memory `_last_write: dict[uid -> monotonic]` and writes `users.last_seen` (via `database.set_last_seen`) only when the last write for that uid is older than `config.PRESENCE_WRITE_SECONDS` (= `PRESENCE_TIMEOUT_SECONDS // 2`). So continuous browsing is a dict lookup; a write happens at most ~once per half-window per active user per worker, and the row is updated in place (zero growth). It deliberately does **not** call `clear_user_cache` (that would defeat the 300s auth cache; the stale cached self-row is irrelevant since presence of *other* users is always read from a fresh row).
**Consent gate (write path).** `touch` checks `presence.recording_allowed(uid)` (the `activity_recording` consent) **after** the per-worker throttle, so the consent read costs at most one query per half-window per active user rather than one per request. A user who withdraws the consent simply stops being written and appears offline; `base.html` shows a `.recording-indicator` while it is on. Never move the check above the throttle.
**Consent gate (write path).** `touch` checks `presence.recording_allowed(uid)` (the `activity_recording` consent) **after** the per-worker throttle, so the consent read costs at most one query per half-window per active user rather than one per request. A user who withdraws the consent simply stops being written and appears offline. Never move the check above the throttle.
**Read path (any worker):** `presence.is_online(user_row)` = `now - last_seen < PRESENCE_TIMEOUT_SECONDS` (env `DEVPLACE_PRESENCE_TIMEOUT_SECONDS`, default 60). Profile (`routers/profile/index.py` -> `profile_online`) and messages (`routers/messages.py` seed) read `last_seen` off the user row they already loaded - no extra query. Exposed as the Jinja global `is_online(user)` (`templating.py`), on `UserOut.last_seen` and `ProfileOut.profile_online`. This is the **only** cross-worker-correct approach here because pub/sub is in-process.

View File

@ -106,7 +106,7 @@ The gate is at exactly one place: `GatewayService.consent_denied` in `services/o
`container_credentials` gates `containers/api.validate_run_as`: a container configured to run as **someone else** would inject that person's real `DEVPLACE_API_KEY` into software they do not operate, so it is refused unless they granted the consent. Running a container as yourself never asks - you are the one handing over your own credential.
`activity_recording` gates `presence.touch`, checked **after** the per-worker throttle so the consent read costs at most one query per half-window per user. Withdraw it and you simply appear offline. The indicator is the `.recording-indicator` in `base.html`, rendered from the `activity_recording_on(user)` Jinja global.
`activity_recording` gates `presence.touch`, checked **after** the per-worker throttle so the consent read costs at most one query per half-window per user. Withdraw it and you simply appear offline. The consent is managed on the profile privacy tab; no page chrome advertises its state.
## Terms re-acceptance

View File

@ -1375,35 +1375,6 @@ body:has(.page-messages) {
}
.recording-indicator {
position: fixed;
left: var(--space-lg);
bottom: calc(var(--space-2xl) + var(--space-2xl));
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius);
background: var(--bg-card);
border: 1px solid var(--border-light);
color: var(--text-muted);
font-size: 0.75rem;
z-index: var(--z-fab);
will-change: transform;
}
.recording-indicator a {
color: var(--text-muted);
}
.recording-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--danger);
flex: none;
}
.maturity-gate {
padding: var(--space-2xl);
text-align: center;

View File

@ -212,13 +212,6 @@
</footer>
{% endblock %}
{% if user and activity_recording_on(user) %}
<div class="recording-indicator" role="status" aria-live="off" title="Your presence and session activity are recorded while you are signed in">
<span class="recording-dot" aria-hidden="true"></span>
<a href="/profile/{{ user['username'] }}?tab=privacy">Activity recording on</a>
</div>
{% endif %}
{%- set _response_time = response_time_ms(request) -%}
{%- if _response_time %}<div class="response-time-indicator" title="Server response time" aria-hidden="true">{{ _response_time }} ms</div>{% endif -%}

View File

@ -58,13 +58,6 @@ templates.env.globals["is_self"] = is_self
templates.env.globals["guest_disabled"] = guest_disabled
templates.env.globals["is_online"] = presence.is_online
def activity_recording_on(user) -> bool:
return bool(user) and presence.recording_allowed(user.get("uid", ""))
templates.env.globals["activity_recording_on"] = activity_recording_on
from devplacepy.docs_devrant import devrant_endpoints
templates.env.globals["devrant_endpoints"] = devrant_endpoints