neiam
/fieri-forever
the flavortown lunch engine
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
Log in to mark this repository.
Obsessed { since } rank; Fieri on the landing page
504ebaf · Gabriel Morell · 2026-10-28 20:18
Message
{commit_body(@commit)}
Files changed
modified
README.md
+5
−3
| 2 | 2 | |
| 3 | 3 | Where are we going for lunch? Not there again. |
| 4 | 4 | |
| 5 | −People pin restaurants on an OpenStreetMap map and rank each one **Always**, | |
| 6 | −**Positive**, **Neutral** or **Never**. When a group goes out, the app suggests | |
| 5 | +People pin restaurants on an OpenStreetMap map and rank each one **Obsessed** | |
| 6 | +(since a date), **Always**, **Positive**, **Neutral** or **Never**. When a group goes out, the app suggests | |
| 7 | 7 | somewhere from what everyone going likes and where the team hasn't been |
| 8 | 8 | lately, and the group logs where it actually went so the next pick knows. |
| 9 | 9 |
| 94 | 94 | All in `src/suggest.rs`, pure functions with unit tests. For the people going: |
| 95 | 95 | |
| 96 | 96 | - **Veto.** If anyone going ranked a place *Never*, it's out. |
| 97 | −- **Liked.** The group's average weight: Always 4, Positive 2, Neutral 1. | |
| 97 | +- **Liked.** The group's average weight: Obsessed 6, Always 4, Positive 2, | |
| 98 | + Neutral 1. Obsessed records when it started; picking it again keeps that | |
| 99 | + date, and it can be backdated from the rank widget. | |
| 98 | 100 | Unranked counts as Neutral, so nobody has to rank everything. |
| 99 | 101 | - **Freshness.** `1 / (1 + 3 × load)`, where load sums every visit in the last |
| 100 | 102 | 70 days, each decayed by a 10-day half-life. Yesterday's spot keeps about a |
modified
?
+0
−0
Binary file — not rendered.
modified
assets/f/js/map.js
+2
−2
| 22 | 22 | sky: "blueprint", forest: "night", clays: "night", |
| 23 | 23 | }; |
| 24 | 24 | |
| 25 | −// Rank colours, as in the badges: success / lime / neutral / error. | |
| 25 | +// Rank colours, as in the badges: flame / success / lime / neutral / error. | |
| 26 | 26 | const RANK_COLORS = { |
| 27 | − always: "#16a34a", positive: "#84cc16", neutral: "#a8a29e", never: "#dc2626", | |
| 27 | + obsessed: "#ea580c", always: "#16a34a", positive: "#84cc16", neutral: "#a8a29e", never: "#dc2626", | |
| 28 | 28 | }; |
| 29 | 29 | const UNRANKED = "#3b82f6"; |
| 30 | 30 | const CANDIDATE = "#f59e0b"; |
modified
migration/src/lib.rs
+2
−0
| 3 | 3 | mod m20240101_000001_create_auth_tables; |
| 4 | 4 | mod m20261028_000001_create_lunch_tables; |
| 5 | 5 | mod m20261028_000002_create_outings; |
| 6 | +mod m20261028_000003_obsessed; | |
| 6 | 7 | |
| 7 | 8 | pub struct Migrator; |
| 8 | 9 |
| 13 | 14 | Box::new(m20240101_000001_create_auth_tables::Migration), |
| 14 | 15 | Box::new(m20261028_000001_create_lunch_tables::Migration), |
| 15 | 16 | Box::new(m20261028_000002_create_outings::Migration), |
| 17 | + Box::new(m20261028_000003_obsessed::Migration), | |
| 16 | 18 | ] |
| 17 | 19 | } |
| 18 | 20 | } |
added
migration/src/m20261028_000003_obsessed.rs
+46
−0
| 1 | +//! `Obsessed { since }`: a rank stronger than Always, carrying the date the | |
| 2 | +//! obsession began. The rank column already holds the kind as a string | |
| 3 | +//! ("obsessed" fits its 16 chars); the date gets its own column, set only | |
| 4 | +//! when the rank is "obsessed". | |
| 5 | +use sea_orm_migration::prelude::*; | |
| 6 | + | |
| 7 | +#[derive(DeriveMigrationName)] | |
| 8 | +pub struct Migration; | |
| 9 | + | |
| 10 | +#[async_trait::async_trait] | |
| 11 | +impl MigrationTrait for Migration { | |
| 12 | + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { | |
| 13 | + manager | |
| 14 | + .alter_table( | |
| 15 | + Table::alter() | |
| 16 | + .table(Rankings::Table) | |
| 17 | + .add_column(ColumnDef::new(Rankings::ObsessedSince).date().null()) | |
| 18 | + .to_owned(), | |
| 19 | + ) | |
| 20 | + .await | |
| 21 | + } | |
| 22 | + | |
| 23 | + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { | |
| 24 | + // An obsession without its date isn't representable; fall back to | |
| 25 | + // the next strongest rank. | |
| 26 | + manager | |
| 27 | + .exec_stmt( | |
| 28 | + Query::update() | |
| 29 | + .table(Rankings::Table) | |
| 30 | + .value(Rankings::Rank, "always") | |
| 31 | + .and_where(Expr::col(Rankings::Rank).eq("obsessed")) | |
| 32 | + .to_owned(), | |
| 33 | + ) | |
| 34 | + .await?; | |
| 35 | + manager | |
| 36 | + .alter_table(Table::alter().table(Rankings::Table).drop_column(Rankings::ObsessedSince).to_owned()) | |
| 37 | + .await | |
| 38 | + } | |
| 39 | +} | |
| 40 | + | |
| 41 | +#[derive(DeriveIden)] | |
| 42 | +enum Rankings { | |
| 43 | + Table, | |
| 44 | + Rank, | |
| 45 | + ObsessedSince, | |
| 46 | +} |
modified
src/entities/rankings.rs
+78
−10
Click to load diff…
modified
src/handlers/areas.rs
+3
−1
Click to load diff…
modified
src/handlers/lunch.rs
+1
−1
Click to load diff…
modified
src/handlers/outings.rs
+2
−2
Click to load diff…
modified
src/handlers/restaurants.rs
+59
−13
Click to load diff…
modified
src/lib.rs
+1
−1
Click to load diff…
modified
src/suggest.rs
+25
−3
Click to load diff…
modified
templates/_macros.html
+6
−5
Click to load diff…
modified
templates/areas/show.html
+1
−1
Click to load diff…
modified
templates/index.html
+4
−1
Click to load diff…
modified
templates/lunch/_plan.html
+1
−1
Click to load diff…
modified
templates/restaurants/_rank.html
+24
−15
Click to load diff…
modified
templates/restaurants/show.html
+1
−1
Click to load diff…
modified
tests/templates.rs
+15
−1
Click to load diff…
Parents: 7def6a5