Commit graph

29 commits

Author SHA1 Message Date
80de61451c Fix bullet indent on CSV/ADIF upload tabs
list-inside aligned wrapped lines with the bullet marker; use
list-outside + pl-5 so wrapped text indents cleanly past the bullet.
2026-04-12 13:16:06 -05:00
eb1e80958c Normalize ADIF MODE/SUBMODE and document the mapping
- AdifImport.normalize_mode/2 maps ADIF MODE (and SUBMODE when present)
  onto the fixed set of modes the site accepts: CW/SSB/FM/FT8/FT4/Q65.
  SUBMODE takes precedence so `MODE=MFSK, SUBMODE=FT8` correctly imports
  as FT8. USB/LSB/DSB all become SSB; NBFM/WFM become FM.
- Unknown modes (RTTY, PSK31, etc.) map to nil so the row still imports
  — mode is optional on the submission path now.
- AdifImport.mode_mapping_reference/0 returns the user-facing list of
  recognized inputs and their mappings.
- Submit page's ADIF tab renders that list in a table so users can see
  upfront what will happen to their file before uploading.
2026-04-12 13:15:31 -05:00
6c334d6e18 Cache /contacts, fix map blink, make mode optional
- Add contacts_inserted_at_desc_id_desc_idx so /contacts list runs as an
  Index Scan (~0.4ms) instead of a Seq Scan + top-N heapsort (~77ms on
  58k rows)
- Add Microwaveprop.Cache: tiny ETS-backed TTL cache for memoizing
  expensive-but-stale-tolerant values
- Cache total_entries for unsearched /contacts page loads (30s TTL,
  invalidated on insert)
- Cache the entire /contacts/map payload (pre-encoded JSON + band list),
  moving load_contacts into Radio.contact_map_payload; invalidated on
  new contact insert. Mount goes from ~150-300ms to ~5ms.
- Fix /map overlay blinking on load: reuse the Leaflet GridLayer across
  renderScores calls and just redraw() against the updated ScoreGrid,
  instead of removeLayer + new layer which flashed between tile regens
- Make mode optional on submission: schema change (null: true),
  submission_changeset no longer requires it, blank strings normalise to
  nil, CSV import accepts 6-column (no mode) or 7-column layouts
- core_components .input adds a red asterisk to labels when required,
  giving users a visual cue for which fields must be filled on /submit
2026-04-12 12:47:25 -05:00
dd13a5f2a5 Fix three security issues
1. Prevent user_id impersonation in contact submissions
   - Remove user_id from submission_changeset cast fields
   - Pass user_id as a separate server-side argument to create_contact/2
   - Client form params can no longer forge account-linked contacts

2. Restrict flag toggle to admins only
   - Add admin? guard to toggle_flag event handler
   - Hide flag button from non-admin users in template

3. Reset enrichment on timestamp edits
   - Add qso_timestamp to the fields that trigger enrichment reset
   - Prevents stale weather/HRRR/IEMRE data after time changes
2026-04-12 10:31:23 -05:00
d5d0c32745 Use daisyUI components for stats, alerts, cards, and tabs
- about: stat cards → daisyUI stat, warning/donate boxes → alert
- submit: tab buttons → daisyUI tabs-box, info/instruction boxes → alert
- backfill: enrichment/DB stat boxes → daisyUI stat
- beacon show: stats container → daisyUI card
- contact show: info/status boxes → alert, data source cards → card
- ADIF: strip APP_ prefix from app-defined fields, normalize grid case
2026-04-12 09:20:20 -05:00
c3becdac9f Show beacon submitter callsign, add donate link, prefer 8-char grids
- Add belongs_to :user on Beacon schema, preload in get_beacon!/1
- Show "Submitted by {callsign}" on beacon detail page
- Add NTMS donation link on the about page
- Change grid preference text to 8 characters (e.g. EM12kp37)
2026-04-11 18:08:18 -05:00
d990884cea Force 24-hour time on UTC timestamp inputs 2026-04-11 17:44:39 -05:00
5bcf579009 Add ADIF file upload for contact submission
Parse ADIF tagged-data format with fuzzy frequency-to-band matching
(nearest microwave band for any freq >= 900 MHz). Supports STATION_CALLSIGN,
OPERATOR, CALL, GRIDSQUARE, MY_GRIDSQUARE, FREQ, BAND, QSO_DATE, TIME_ON.
Same dedup and preview/commit flow as CSV upload.

Also fix select dropdown text alignment in daisyUI.
2026-04-11 17:39:05 -05:00
25c703401b Link to existing contact on duplicate submission
Return the conflicting contact from create_contact so the UI can redirect
to it with a flash message instead of just showing a form error.
2026-04-11 17:30:46 -05:00
4ca8c5d3bc Add Q65 contact mode 2026-04-11 17:21:45 -05:00
ea0c41ef50 Fix crash on /submit when LiveStash restores CSV tab without csv_result assign
Set all assigns before LiveStash recovery so reconnecting to the CSV
tab doesn't crash on missing :csv_result / :csv_preview keys.
2026-04-10 14:04:16 -05:00
f21277cf4f Show upload progress and submission confirmation on /submit
Add a per-entry progress bar (with cancel) while a CSV streams in, and
replace the small post-commit alert with a prominent "X contacts
submitted" confirmation card.
2026-04-09 13:46:54 -05:00
5724b33e8f Link submissions to the logged-in user on /submit
Contacts now carry a user_id FK to users. When a logged-in user
submits a contact (single or CSV upload), the server injects their
user_id and the email from their account into the submission params,
and the visible email input is replaced with a hidden input holding
that value — logged-in users don't have to retype their address.

The submission changeset now requires at least one of user_id or
submitter_email (rather than hard-requiring email), and email format
is only validated when one is actually present.

Reworded the submit-page blurb from "10 GHz to 241 GHz" to "902 MHz
and up" so it matches the actual band coverage of the project.
2026-04-09 13:01:49 -05:00
44b169b234 CSV upload preview with duplicate detection before commit
Uploads now show a review page with three summary cards (valid,
duplicates, invalid), tables for invalid and duplicate rows, and a
sample of the first 20 valid rows. Nothing is written to the database
until the user clicks "Looks good — submit N contacts".

Duplicate detection treats two rows as the same contact if they share
the same pair of (callsign, grid) tuples (direction-agnostic), the
same band, and timestamps within 60 minutes. Dedup runs against both
existing DB contacts (single band/time-scoped query) and earlier rows
in the same upload, and the preview labels which side matched.

CsvImport grows preview/2 + commit/1; the old import/2 is kept as a
thin backward-compat wrapper that skips dedup. Added 11 new CsvImport
tests and reworked the SubmitLive CSV tests for the two-step flow.
2026-04-09 12:30:10 -05:00
27170b5139 Merge auth links into main nav and lower password min to 8
- Register/Log in (or callsign/Settings/Log out) now live next to
  the Map/Path/Rover links in the main header instead of a separate
  top menu bar
- Add on_mount in UserAuth to assign current_scope on LiveView mount,
  and pass current_scope through to Layouts.app from every LiveView
- Drop the old top <ul> from root.html.heex
- Password minimum lowered from 12 to 8 characters
2026-04-08 10:39:51 -05:00
cfaef287e4 Add 902-5760 MHz bands, centralize band options
New BandConfig entries for 902, 1296, 2304, 3456, 5760 MHz:
- All beneficial humidity effect (like 10 GHz)
- Near-zero gaseous absorption and rain attenuation
- Ranges: 902 MHz typical 400 km, 5760 MHz typical 220 km
- Same seasonal curves as 10 GHz (ducting-driven)

BandConfig.band_options/0 generates dropdown options from configs.
All pages (path, rover, submit) use centralized band_options instead
of hardcoded lists. Map page already used BandConfig.all_bands().
10 GHz remains the default on all pages.
2026-04-07 16:39:25 -05:00
d275e9e7c4
fix enrichment 2026-04-02 15:30:41 -05:00
c1da0f20b1
Add LiveStash for state recovery across reconnects
- Installed live_stash ~> 0.1 with browser memory adapter
- Map page: recovers selected_band and selected_time on reconnect
- Submit page: recovers active_tab (single/csv) on reconnect
- JS params initialized with initLiveStash wrapper
2026-04-02 13:12:17 -05:00
fd33eff8bc
Add required attribute to all single contact form fields 2026-04-01 15:56:25 -05:00
05654289af
Accept various date/time formats in CSV import
Parse US dates (6/15/2024 2:30 PM), 24h (06/15/2024 14:30),
dashes (06-15-2024 14:30), compact (20240615 1430), date-only
(2024-06-15), and ISO 8601 — all normalized to UTC before insert.
2026-04-01 15:35:35 -05:00
bc70b38e93
Add info box about contact availability after submission 2026-04-01 15:32:44 -05:00
4e092a0cf5
Use bulleted list for CSV upload instructions 2026-04-01 15:31:38 -05:00
2b11b872d9
Restyle submit page tabs as segmented control 2026-04-01 15:31:09 -05:00
18a291555c
Add CSV bulk upload to /submit page
Adds a tabbed UI with single-contact form and CSV upload. Users can
download a sample CSV, upload their file, and get partial import with
per-row error reporting. Enrichment jobs enqueue for each imported contact.
2026-04-01 15:05:51 -05:00
ea96c93e2d
Rename QSO to Contact in UI, add higher bands, improve submit page
- All menus and UI text now say Contacts instead of QSOs
- Add 68, 122, 134, 241 GHz bands to submit form and validation
- Add info box on submit page explaining why contacts matter
- Larger submit button with icon
- Make HRRR partition migration idempotent for partial re-runs
2026-04-01 12:28:24 -05:00
254e64dedc
Rename qsos to contacts throughout codebase, keep DB table name
Rename all modules, functions, variables, routes, and UI text from
qso/qsos to contact/contacts. Database table stays as "qsos" to avoid
migration. Add /qsos -> /contacts redirects for old URLs.
2026-04-01 11:25:04 -05:00
40d1fa03aa
QSO submission triggers enrichment directly, fix prod badarith crash
- Add enqueue_for_qso/1 to directly enqueue weather/HRRR/terrain/IEMRE
  jobs for a single user-submitted QSO (no cron, no bulk processing)
- Submit flow calls enqueue_for_qso instead of generic enqueue worker
- Add enrichment queues to prod config for on-demand processing
- Guard against HRRR fill values in store_hrrr_profiles (fixes badarith)
- Filter QSOs without pos2 in build_terrain_jobs
2026-03-31 12:29:39 -05:00
fe3c8812a0
Harden /submit route for production
- Defensive grid-to-coordinate resolution in create_qso (case instead of crash on match failure)
- Log warning when Oban weather enqueue fails instead of silently dropping
- Add 30s per-session submission cooldown to prevent rapid-fire submissions
2026-03-29 17:24:12 -05:00
7d0978f7d5
Add /submit route for user QSO submission
Maidenhead grid module converts grid squares to lat/lon coordinates.
Submission form validates grids, bands, modes, and email, computes
positions and distance, then triggers the weather/HRRR/terrain
processing pipeline via Oban.
2026-03-29 16:46:35 -05:00