6 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.8 55db677637 Submissions: make the resolved-set durable so handled items stay handled
Resolved submissions were resurfacing (most visibly after a cache clear)
because the admin resolved-set wasn't durable: it was never mirrored (relays
pruned it) and the read-modify-write could republish a SHRUNK replaceable
list when a cold-load read missed the current set.

- Device-local resolved-id cache (localStorage): grows only, backs up the
  relay list. Hides handled items even if a relay read momentarily misses,
  and makes markSubmissionResolved loss-proof — it folds every locally-known
  resolved id into each republish, so a missed read can't drop entries.
- Mirror the resolved-set on each fetch (re-broadcast) so relays keep it
  alive, same as we do for pending submissions.
- Persist relay-known resolved ids into the local cache on fetch.
- Belt-and-suspenders: an application whose applicant is already whitelisted
  is treated as handled even if the resolved-set were lost entirely
  (callers now pass accessControl.getWhitelist()).
- tests: whitelist-hide, local-hide after a cold read, and loss-proof
  republish (earlier id carried forward despite a missed read).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 17:02:20 -04:00
thePR0M3TH3ANandClaude Opus 4.8 5eb7545a3f Submissions persistence: publish to nos.lol + admin re-broadcast mirror
Submissions are signed by throwaway ephemeral keys and public relays prune
events from pubkeys with no social graph, so the queue quietly evaporated.

- Forms: also publish to nos.lol (better retention, already in the app's
  query set) alongside snort/damus/primal.
- submissionFacade: on each fetch, re-broadcast the still-pending signed
  events back to our relays (publishEventToRelays) so pruning doesn't drop
  them. Best-effort, fire-and-forget — never blocks or fails the fetch;
  no-ops when no relay pool is available.
- test: fetch still returns the pending queue when a pool is present.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 15:48:48 -04:00
thePR0M3TH3ANandClaude Opus 4.8 60157eb743 Appeals: diagnose and handle author-level blocks too
Approving a content appeal now checks WHY the video is hidden and applies
the right fix, instead of only ever touching the per-event block list.

- submissionFacade.js: resolveEventAuthorHex({ eventId }) looks up the event
  and returns its author hex — the authoritative author, so we don't rely on
  the appellant to supply it.
- submissionsSection.js approveAppeal: branch on the real block state.
  * Author-level block (whole npub) → its own strongly-worded confirmation
    ("restores ALL their content"); on confirm, removeFromBlacklist plus any
    event block. Never bundled into the default unblock.
  * Event-level block only → unblock this video (as before).
  * Neither → distinguish "nothing to unblock" from "couldn't verify on
    relays" and just mark the appeal resolved.
- tests: resolveEventAuthorHex (author normalization, blank/not-found).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 10:32:38 -04:00
thePR0M3TH3ANandClaude Opus 4.8 2803f6b56f Submissions: labeled actions + real appeal-driven unblock
Make each admin action self-explanatory and give content appeals a real
effect instead of a dead-end "Dismiss".

- submissionsSection.js: per-type action sets, each button paired with a
  one-line description. Applications show Approve (adds to whitelist) / Deny;
  appeals that name a real event show "Approve & unblock" (removes the video
  from the event block list) / "Keep blocked"; other types show "Mark handled".
- submissionService.js: parse an appeal's `e` tag into targetEventId (trusted
  only when it's a well-formed 64-char hex id).
- iframe-content-appeals-form.html: add a required "Blocked video link or
  event ID" field; regex-validate + normalize a share link / nevent / note /
  hex to the hex event id, tag it as `e`, and include it in the body. Block
  submission when no valid reference is provided.
- CSS: stacked action + hint styling; iframe-form .form-hint.
- tests: cover targetEventId parsing (valid, malformed, absent).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-07 09:52:04 -04:00
thePR0M3TH3ANandClaude Opus 4.8 28b23e0078 submissions(#23): fetch-pending + resolved-set facade
Network layer for the admin Submissions tab. Because submissions are authored by
an ephemeral key, admins can't NIP-09-delete them (relays only honor same-author
deletions), so "handled" state lives in an admin-authored RESOLVED-SET.

- fetchPendingSubmissions({ adminHex, editorHexes }) — lists kind-30083 to the
  admin, subtracts the UNION of every editor's resolved-set (so any moderator's
  action clears it for all), dedupes by claimed applicant (newest wins).
- markSubmissionResolved({ submission, status, actingHex }) — read-modify-write
  the acting moderator's resolved-set (kind-30000, d=bitvid:admin:submissions-
  resolved), appending the submission's event id + status + applicant, republished
  via the active signer.

tests/submission-facade.test.mjs (4): pending excludes resolved + dedupes by
applicant (newest); blank-admin/no-relay guards; resolved-set append keeps prior
entries and records status+applicant; no-op guards. Mock client. 4/4; lint clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-06 20:20:18 -04:00
thePR0M3TH3ANandClaude Opus 4.8 a18230eb70 submissions(#23): foundation — kind-30083 schema, builder, service + tests
First slice of structured submissions (replacing the kind-4 encrypted DM forms).
Pure, hermetic core — no UI or network yet.

- nostrEventSchemas.js: SUBMISSION_KIND=30083 (+ NOTE_TYPES.SUBMISSION, BASE_SCHEMAS
  entry) and buildSubmissionEvent(). PUBLIC + addressable; data in tags: d (id),
  k (type), applicant (npub), p (admin), t=bitvid-submission; free-text in content.
- js/submissions/submissionService.js: SUBMISSION_TYPES + labels, parseSubmissionEvent,
  buildSubmission, generateSubmissionId. Pure — unit-testable with no relays/signer.
- constants.js: FEATURE_SUBMISSIONS (default OFF until the admin UI + forms ship).
- tests/submission-service.test.mjs: 8 scenarios (build tags/type/default, d-tag
  required, parse structure/reject/unknown-type→other, build→parse round-trip of
  every type, id generation).
- check-file-size.mjs: bump nostrEventSchemas grandfather 3250→3541 (adding a new
  event type to the schema registry is the prescribed pattern).
- docs/nostr-event-schemas.md: catalogue row.

Schema validation ✨, lint, build all pass; tests 8/8.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-06 20:17:47 -04:00