diff --git a/pointercrate-demonlist-pages/static/js/modules/statsviewer.js b/pointercrate-demonlist-pages/static/js/modules/statsviewer.js index 19b60bd1f..57799528d 100644 --- a/pointercrate-demonlist-pages/static/js/modules/statsviewer.js +++ b/pointercrate-demonlist-pages/static/js/modules/statsviewer.js @@ -110,7 +110,7 @@ export class StatsViewer extends FilteredPaginator { this._hardest.appendChild( hardest === undefined ? document.createTextNode("None") - : this.formatDemon(hardest, "/demonlist/permalink/" + hardest.id + "/") + : this.formatDemon(hardest) ); } @@ -140,15 +140,11 @@ export class StatsViewer extends FilteredPaginator { element.style.opacity = ".5"; } - if (link) { - let a = document.createElement("a"); - a.href = link; - a.textContent = demon.name; + let a = document.createElement("a"); + a.href = link ?? "/demonlist/permalink/" + demon.id + "/"; + a.textContent = demon.name; - element.appendChild(a); - } else { - element.textContent = demon.name; - } + element.appendChild(a); return element; } diff --git a/pointercrate-demonlist-pages/static/js/statsviewer/individual.js b/pointercrate-demonlist-pages/static/js/statsviewer/individual.js index 9c0caf6c4..86ee9f4b9 100644 --- a/pointercrate-demonlist-pages/static/js/statsviewer/individual.js +++ b/pointercrate-demonlist-pages/static/js/statsviewer/individual.js @@ -82,9 +82,7 @@ class IndividualStatsViewer extends StatsViewer { formatDemonsInto(element, demons) { formatInto( element, - demons.map((demon) => - this.formatDemon(demon, "/demonlist/permalink/" + demon.id + "/") - ) + demons.map((demon) => this.formatDemon(demon)) ); } @@ -92,10 +90,7 @@ class IndividualStatsViewer extends StatsViewer { formatInto( element, records.map((record) => { - let demon = this.formatDemon( - record.demon, - record.video ?? "/demonlist/permalink/" + record.demon.id + "/" - ); + let demon = this.formatDemon(record.demon, record.video); if (record.progress !== 100) { demon.appendChild( document.createTextNode(" (" + record.progress + "%)") diff --git a/pointercrate-demonlist-pages/static/js/statsviewer/nation.js b/pointercrate-demonlist-pages/static/js/statsviewer/nation.js index 86cf813b7..efff52b82 100644 --- a/pointercrate-demonlist-pages/static/js/statsviewer/nation.js +++ b/pointercrate-demonlist-pages/static/js/statsviewer/nation.js @@ -23,7 +23,7 @@ class NationStatsViewer extends StatsViewer { let nationData = response.data.data; - this.setName(nationData.nation.nation, nationData.nation); + this.setName(nationData.nation, nationData); let beaten = []; let progress = []; @@ -44,16 +44,12 @@ class NationStatsViewer extends StatsViewer { } else { beaten.push(record); - if (hardest === undefined || record.position < hardest.position) { - hardest = { - name: record.demon, - position: record.position, - id: record.id, - }; + if (hardest === undefined || record.demon.position < hardest.position) { + hardest = record.demon; } - if (record.position > this.list_size) - if (record.position <= this.extended_list_size) ++extended; + if (record.demon.position > this.list_size) + if (record.demon.position <= this.extended_list_size) ++extended; else ++legacy; } } @@ -61,19 +57,15 @@ class NationStatsViewer extends StatsViewer { let amountBeaten = beaten.length - extended - legacy; for (let record of nationData.verified) { - players.add(record.player); - - if (hardest === undefined || record.position < hardest.position) { - hardest = { - name: record.demon, - position: record.position, - id: record.id, - }; + record.players.forEach(players.add, players); + + if (hardest === undefined || record.demon.position < hardest.position) { + hardest = record.demon } - if (!beaten.some((d) => d.id === record.id)) - if (record.position > this.list_size) - if (record.position <= this.extended_list_size) ++extended; + if (!beaten.some((d) => d.demon.id === record.demon.id)) + if (record.demon.position > this.list_size) + if (record.demon.position <= this.extended_list_size) ++extended; else ++legacy; else ++amountBeaten; } @@ -84,14 +76,14 @@ class NationStatsViewer extends StatsViewer { this.setCompletionNumber(amountBeaten, extended, legacy); nationData.unbeaten.sort((r1, r2) => r1.name.localeCompare(r2.name)); - beaten.sort((r1, r2) => r1.demon.localeCompare(r2.demon)); + beaten.sort((r1, r2) => r1.demon.name.localeCompare(r2.demon.name)); progress.sort((r1, r2) => r2.progress - r1.progress); - nationData.created.sort((r1, r2) => r1.demon.localeCompare(r2.demon)); + nationData.created.sort((r1, r2) => r1.demon.name.localeCompare(r2.demon.name)); formatInto( this._unbeaten, nationData.unbeaten.map((demon) => - this.formatDemon(demon, "/demonlist/permalink/" + demon.id + "/") + this.formatDemon(demon) ) ); formatInto( @@ -106,10 +98,7 @@ class NationStatsViewer extends StatsViewer { this._created, nationData.created.map((creation) => { return this.makeTooltip( - this.formatDemon( - { name: creation.demon, position: creation.position }, - "/demonlist/permalink/" + creation.id + "/" - ), + this.formatDemon(creation.demon), "(Co)created by " + creation.players.length + " player" + @@ -123,12 +112,9 @@ class NationStatsViewer extends StatsViewer { this._verified, nationData.verified.map((verification) => { return this.makeTooltip( - this.formatDemon( - { name: verification.demon, position: verification.position }, - "/demonlist/permalink/" + verification.id + "/" - ), + this.formatDemon(verification.demon), "Verified by: ", - verification.player + verification.players.join(", ") ); }) ); @@ -136,12 +122,9 @@ class NationStatsViewer extends StatsViewer { this._published, nationData.published.map((publication) => { return this.makeTooltip( - this.formatDemon( - { name: publication.demon, position: publication.position }, - "/demonlist/permalink/" + publication.id + "/" - ), + this.formatDemon(publication.demon), "Published by: ", - publication.player + publication.players.join(", ") ); }) ); @@ -167,10 +150,7 @@ class NationStatsViewer extends StatsViewer { } formatDemonFromRecord(record) { - let baseElement = this.formatDemon( - { name: record.demon, position: record.position }, - "/demonlist/permalink/" + record.id + "/" - ); + let baseElement = this.formatDemon(record.demon); if (record.progress !== 100) baseElement.appendChild( @@ -197,7 +177,7 @@ $(window).on("load", function () { ); window.statsViewer.initialize(); window.statsViewer.addSelectionListener((selected) => - map.select(selected.nation.country_code) + map.select(selected.country_code) ); map.addSelectionListener((country, _) => { diff --git a/pointercrate-demonlist/src/nationality/get.rs b/pointercrate-demonlist/src/nationality/get.rs index 033c6b57d..87328ec6d 100644 --- a/pointercrate-demonlist/src/nationality/get.rs +++ b/pointercrate-demonlist/src/nationality/get.rs @@ -1,7 +1,7 @@ use crate::{ demon::MinimalDemon, error::{DemonlistError, Result}, - nationality::{BestRecord, MiniDemon, MiniDemonWithPlayers, Nationality, NationalityRecord, Subdivision}, + nationality::{BestRecord, MiniDemonWithPlayers, Nationality, NationalityRecord, Subdivision}, }; use futures::stream::StreamExt; use sqlx::{Error, PgConnection}; @@ -158,11 +158,13 @@ pub async fn created_in(nation: &Nationality, connection: &mut PgConnection) -> let row = row?; match creations.last_mut() { - Some(mini_demon) if mini_demon.demon == row.demon_name => mini_demon.players.push(row.player_name), + Some(mini_demon) if mini_demon.demon.name == row.demon_name => mini_demon.players.push(row.player_name), _ => creations.push(MiniDemonWithPlayers { - id: row.demon, - demon: row.demon_name, - position: row.position, + demon: MinimalDemon { + id: row.demon, + name: row.demon_name, + position: row.position, + }, players: vec![row.player_name], }), } @@ -171,7 +173,7 @@ pub async fn created_in(nation: &Nationality, connection: &mut PgConnection) -> Ok(creations) } -pub async fn verified_in(nation: &Nationality, connection: &mut PgConnection) -> Result> { +pub async fn verified_in(nation: &Nationality, connection: &mut PgConnection) -> Result> { let mut stream = sqlx::query!( r#"select demons.id as demon, demons.name::text as "demon_name!", demons.position, players.name::text as "player_name!" from demons inner join players on players.id=verifier where nationality=$1"#, nation.iso_country_code).fetch(connection); @@ -180,18 +182,20 @@ pub async fn verified_in(nation: &Nationality, connection: &mut PgConnection) -> while let Some(row) = stream.next().await { let row = row?; - demons.push(MiniDemon { - id: row.demon, - demon: row.demon_name, - position: row.position, - player: row.player_name, + demons.push(MiniDemonWithPlayers { + demon: MinimalDemon { + id: row.demon, + name: row.demon_name, + position: row.position, + }, + players: vec![row.player_name], }); } Ok(demons) } -pub async fn published_in(nation: &Nationality, connection: &mut PgConnection) -> Result> { +pub async fn published_in(nation: &Nationality, connection: &mut PgConnection) -> Result> { let mut stream = sqlx::query!( r#"select demons.id as demon, demons.name::text as "demon_name!", demons.position, players.name::text as "player_name!" from demons inner join players on players.id=publisher where nationality=$1"#, nation.iso_country_code).fetch(connection); @@ -200,11 +204,13 @@ pub async fn published_in(nation: &Nationality, connection: &mut PgConnection) - while let Some(row) = stream.next().await { let row = row?; - demons.push(MiniDemon { - id: row.demon, - demon: row.demon_name, - position: row.position, - player: row.player_name, + demons.push(MiniDemonWithPlayers { + demon: MinimalDemon { + id: row.demon, + name: row.demon_name, + position: row.position, + }, + players: vec![row.player_name], }); } @@ -224,11 +230,13 @@ pub async fn best_records_in(nation: &Nationality, connection: &mut PgConnection let row = row?; match records.last_mut() { - Some(record) if record.demon == row.demon_name => record.players.push(row.player_name), + Some(record) if record.demon.name == row.demon_name => record.players.push(row.player_name), _ => records.push(BestRecord { - id: row.demon_id, - demon: row.demon_name, - position: row.position, + demon: MinimalDemon { + id: row.demon_id, + name: row.demon_name, + position: row.position, + }, progress: row.progress, players: vec![row.player_name], }), diff --git a/pointercrate-demonlist/src/nationality/mod.rs b/pointercrate-demonlist/src/nationality/mod.rs index 67a00f17e..a7c101c2b 100644 --- a/pointercrate-demonlist/src/nationality/mod.rs +++ b/pointercrate-demonlist/src/nationality/mod.rs @@ -18,38 +18,28 @@ pub struct Nationality { #[derive(Debug, Serialize, Hash)] pub struct BestRecord { - id: i32, - demon: String, - position: i16, progress: i16, + demon: MinimalDemon, players: Vec, } -#[derive(Debug, Serialize, Hash)] -pub struct MiniDemon { - id: i32, - demon: String, - position: i16, - player: String, -} - #[derive(Debug, Serialize, Hash)] pub struct MiniDemonWithPlayers { - id: i32, - demon: String, - position: i16, + demon: MinimalDemon, players: Vec, } +/// The [`Nationality`] equivalent of [`FullPlayer`], very roughly #[derive(Debug, Hash, Serialize)] pub struct NationalityRecord { + #[serde(flatten)] pub nation: Nationality, #[serde(rename = "records")] pub best_records: Vec, pub created: Vec, - pub verified: Vec, - pub published: Vec, + pub verified: Vec, + pub published: Vec, pub unbeaten: Vec, }