|
|
|
@ -3,11 +3,50 @@ mod filters;
|
|
|
|
|
mod model;
|
|
|
|
|
mod views;
|
|
|
|
|
mod languages;
|
|
|
|
|
mod traits;
|
|
|
|
|
|
|
|
|
|
macro_rules! other_lang_urls {
|
|
|
|
|
($lang:expr, $template:ident) => {
|
|
|
|
|
$lang.other_langs().map(move |olang| {
|
|
|
|
|
LangLink {
|
|
|
|
|
name: olang.native_name(),
|
|
|
|
|
href: Into::<Locale>::into($lang)
|
|
|
|
|
.translate(
|
|
|
|
|
$template::URL_KEY,
|
|
|
|
|
vec![
|
|
|
|
|
("lang", olang.to_string().into())
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
.expect("Unable to find key {key} in locale {self}.")
|
|
|
|
|
}
|
|
|
|
|
}).collect()
|
|
|
|
|
};
|
|
|
|
|
($lang:expr, $template:ident, $($k:literal => $v:expr),+) => {
|
|
|
|
|
$lang.other_langs().map(move |olang| {
|
|
|
|
|
LangLink {
|
|
|
|
|
name: olang.native_name(),
|
|
|
|
|
href: Into::<Locale>::into($lang)
|
|
|
|
|
.translate(
|
|
|
|
|
$template::URL_KEY,
|
|
|
|
|
hashmap_macro::hashmap![
|
|
|
|
|
"lang" => olang.to_string().into(),
|
|
|
|
|
$($k => $v.into()),+
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
.expect("Unable to find key {key} in locale {self}.")
|
|
|
|
|
}
|
|
|
|
|
}).collect()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use traits::TemplateUrl;
|
|
|
|
|
use static_assertions::assert_impl_all;
|
|
|
|
|
#[macro_use]
|
|
|
|
|
extern crate ibihf_macros;
|
|
|
|
|
use askama::i18n::{langid, Locale};
|
|
|
|
|
askama::i18n::load!(LOCALES);
|
|
|
|
|
|
|
|
|
|
use crate::model::{Division, Game, GamePlayer, League, Player, Shot, Team, Language};
|
|
|
|
|
use crate::model::{Division, Game, League, Player, Language};
|
|
|
|
|
use views::{GoalDetails, PlayerStats, ShotDetails, TeamStats, IihfStatsI64};
|
|
|
|
|
use languages::{
|
|
|
|
|
SupportedLanguage,
|
|
|
|
@ -18,31 +57,22 @@ use askama::Template;
|
|
|
|
|
use axum::{
|
|
|
|
|
extract::{Path, State},
|
|
|
|
|
http::StatusCode,
|
|
|
|
|
response::{IntoResponse, Json},
|
|
|
|
|
response::IntoResponse,
|
|
|
|
|
routing::get,
|
|
|
|
|
Router,
|
|
|
|
|
};
|
|
|
|
|
use axum_macros::debug_handler;
|
|
|
|
|
use ormx::Table;
|
|
|
|
|
use sqlx::{Pool, Postgres};
|
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
|
|
const VERSION: &str = "0.3.4";
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[template(path = "hello.html")]
|
|
|
|
|
struct HelloTemplate<'a> {
|
|
|
|
|
name: &'a str,
|
|
|
|
|
years: i32,
|
|
|
|
|
}
|
|
|
|
|
const VERSION: &str = "0.3.5";
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[template(path = "language_list.html")]
|
|
|
|
|
struct LanguageListTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
pub loc: Locale<'a>,
|
|
|
|
|
pub url_name: &'a str,
|
|
|
|
|
pub lang_links: Vec<LangLink>,
|
|
|
|
|
pub lang: SupportedLanguage,
|
|
|
|
|
pub languages: Vec<Language>,
|
|
|
|
@ -53,7 +83,6 @@ struct LanguageListTemplate<'a> {
|
|
|
|
|
struct BoxScoreTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
goals: Vec<GoalDetails>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -62,7 +91,6 @@ struct BoxScoreTemplate<'a> {
|
|
|
|
|
struct IndividualGamePointsTableTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
players: Vec<PlayerStats>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -72,54 +100,54 @@ struct TeamGameStatsTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
teams: Vec<TeamStats>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[urls(url_key = "league_url", url_key_template = "league_url_tmpl")]
|
|
|
|
|
#[template(path = "division_list.html")]
|
|
|
|
|
struct DivisionListTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
url_name: &'a str,
|
|
|
|
|
lang_links: Vec<LangLink>,
|
|
|
|
|
league: League,
|
|
|
|
|
divisions: Vec<Division>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
assert_impl_all!(DivisionListTemplate: TemplateUrl);
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[urls(url_key = "root_url", url_key_template = "root_url_tmpl")]
|
|
|
|
|
#[template(path = "league_list.html")]
|
|
|
|
|
struct LeagueListTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
url_name: &'a str,
|
|
|
|
|
lang_links: Vec<LangLink>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
leagues: Vec<League>,
|
|
|
|
|
heading: String,
|
|
|
|
|
}
|
|
|
|
|
assert_impl_all!(LeagueListTemplate: TemplateUrl);
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[template(path="partials/iihf_team_stats_table.html")]
|
|
|
|
|
struct IihfTeamStatsTableTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
iihf_stats: Vec<IihfStatsI64>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[urls(url_key = "division_url", url_key_template = "division_url_tmpl")]
|
|
|
|
|
#[template(path = "game_list.html")]
|
|
|
|
|
struct GameListTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
url_name: &'a str,
|
|
|
|
|
lang_links: Vec<LangLink>,
|
|
|
|
|
division: Division,
|
|
|
|
|
iihf_team_stats_table: IihfTeamStatsTableTemplate<'a>,
|
|
|
|
|
games: Vec<Game>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
assert_impl_all!(GameListTemplate: TemplateUrl);
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[template(path = "partials/play_by_play_table.html")]
|
|
|
|
@ -127,15 +155,14 @@ struct ShotsTableTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
shots: Vec<ShotDetails>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[urls(url_key = "game_url", url_key_template = "game_url_tmpl")]
|
|
|
|
|
#[template(path = "game_score_page.html")]
|
|
|
|
|
struct GameScorePageTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
url_name: &'a str,
|
|
|
|
|
lang_links: Vec<LangLink>,
|
|
|
|
|
game: Game,
|
|
|
|
|
division: Division,
|
|
|
|
@ -145,20 +172,22 @@ struct GameScorePageTemplate<'a> {
|
|
|
|
|
play_by_play: ShotsTableTemplate<'a>,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
assert_impl_all!(GameScorePageTemplate: TemplateUrl);
|
|
|
|
|
|
|
|
|
|
#[derive(Template)]
|
|
|
|
|
#[derive(Template, TemplateUrl)]
|
|
|
|
|
#[urls(url_key = "player_url", url_key_template = "player_url_tmpl")]
|
|
|
|
|
#[template(path = "player_page.html")]
|
|
|
|
|
pub struct PlayerPageTemplate<'a> {
|
|
|
|
|
#[locale]
|
|
|
|
|
locale: Locale<'a>,
|
|
|
|
|
lang_links: Vec<LangLink>,
|
|
|
|
|
url_name: &'a str,
|
|
|
|
|
player: Player,
|
|
|
|
|
league: League,
|
|
|
|
|
league_stats: PlayerStats,
|
|
|
|
|
lifetime_stats: PlayerStats,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
}
|
|
|
|
|
assert_impl_all!(PlayerPageTemplate: TemplateUrl);
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct ServerState {
|
|
|
|
@ -174,12 +203,10 @@ async fn main() {
|
|
|
|
|
let router = Router::new()
|
|
|
|
|
.route("/", get(language_list))
|
|
|
|
|
.route("/:lang/", get(league_html))
|
|
|
|
|
.route("/:lang/shots/", get(shots_all))
|
|
|
|
|
.route("/:lang/test/", get(test_template))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup("league_url"), get(divisions_for_league_html))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup("division_url"), get(games_for_division_html))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup("game_url"), get(score_for_game_html))
|
|
|
|
|
.route(&SupportedLanguage::French.lookup("game_url"), get(score_for_game_html))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup(DivisionListTemplate::URL_KEY), get(divisions_for_league_html))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup(GameListTemplate::URL_KEY), get(games_for_division_html))
|
|
|
|
|
.route(&SupportedLanguage::English.lookup(GameScorePageTemplate::URL_KEY), get(score_for_game_html))
|
|
|
|
|
.route(&SupportedLanguage::French.lookup(GameScorePageTemplate::URL_KEY), get(score_for_game_html))
|
|
|
|
|
.route("/:lang/player/:name/", get(player_from_name))
|
|
|
|
|
.with_state(state);
|
|
|
|
|
let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
|
|
|
|
@ -198,10 +225,9 @@ async fn language_list(
|
|
|
|
|
.unwrap();
|
|
|
|
|
let lang_list_tmpl = LanguageListTemplate {
|
|
|
|
|
loc: Locale::new(langid!("en-ca"), &LOCALES),
|
|
|
|
|
url_name: "root_url_tmpl",
|
|
|
|
|
lang_links: Vec::new(),
|
|
|
|
|
languages,
|
|
|
|
|
lang: SupportedLanguage::English,
|
|
|
|
|
languages
|
|
|
|
|
};
|
|
|
|
|
(StatusCode::OK, lang_list_tmpl)
|
|
|
|
|
}
|
|
|
|
@ -226,24 +252,17 @@ async fn player_from_name(
|
|
|
|
|
.unwrap();
|
|
|
|
|
let html = PlayerPageTemplate {
|
|
|
|
|
player,
|
|
|
|
|
lang_links: lang.other_langs().map(move |olang| LangLink::from_lang_and_name(olang, &name, "player_url_tmpl")).collect(),
|
|
|
|
|
lang,
|
|
|
|
|
lang_links: other_lang_urls!(lang, PlayerPageTemplate),
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
url_name: "player_url_tmpl",
|
|
|
|
|
league: latest_league,
|
|
|
|
|
league_stats: latest_league_stats,
|
|
|
|
|
lifetime_stats,
|
|
|
|
|
lang,
|
|
|
|
|
};
|
|
|
|
|
(StatusCode::OK, html)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn test_template<'a>() -> HelloTemplate<'a> {
|
|
|
|
|
HelloTemplate {
|
|
|
|
|
name: "Tait",
|
|
|
|
|
years: 24,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
macro_rules! get_all {
|
|
|
|
|
($crud_struct:ident, $func_name:ident) => {
|
|
|
|
|
#[debug_handler]
|
|
|
|
@ -267,23 +286,17 @@ macro_rules! get_by_id {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
async fn league_html(
|
|
|
|
|
State(server_config): State<ServerState>,
|
|
|
|
|
Path(lang): Path<SupportedLanguage>,
|
|
|
|
|
) -> impl IntoResponse {
|
|
|
|
|
let leagues = League::all(&*server_config.db_pool).await.unwrap();
|
|
|
|
|
let heading = match lang {
|
|
|
|
|
SupportedLanguage::English => "IBIHF Leagues",
|
|
|
|
|
SupportedLanguage::French => "League de FIDHS",
|
|
|
|
|
}
|
|
|
|
|
.to_string();
|
|
|
|
|
let leagues_template = LeagueListTemplate {
|
|
|
|
|
lang_links: lang.other_langs().map(move |olang| LangLink::from_lang(olang, "root_url_tmpl")).collect(),
|
|
|
|
|
url_name: "root_url_tmpl",
|
|
|
|
|
lang_links: other_lang_urls!(lang, PlayerPageTemplate),
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
leagues,
|
|
|
|
|
heading,
|
|
|
|
|
lang,
|
|
|
|
|
};
|
|
|
|
|
(StatusCode::OK, leagues_template)
|
|
|
|
@ -301,8 +314,8 @@ async fn divisions_for_league_html(
|
|
|
|
|
.unwrap();
|
|
|
|
|
let html = DivisionListTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
lang_links: lang.other_langs().map(move |olang| LangLink::from_lang_and_id(olang, league_id, "league_url_tmpl")).collect(),
|
|
|
|
|
url_name: "league_url_tmpl",
|
|
|
|
|
// TODO: add league_id here
|
|
|
|
|
lang_links: other_lang_urls!(lang, PlayerPageTemplate, "id" => league.id),
|
|
|
|
|
league,
|
|
|
|
|
divisions,
|
|
|
|
|
lang,
|
|
|
|
@ -325,13 +338,11 @@ async fn games_for_division_html(
|
|
|
|
|
.unwrap();
|
|
|
|
|
let games_template = GameListTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
lang_links: lang.other_langs().map(move |olang| LangLink::from_lang_and_id(olang, division_id, "division_url_tmpl")).collect(),
|
|
|
|
|
url_name: "division_url_tmpl",
|
|
|
|
|
lang_links: other_lang_urls!(lang, GameListTemplate, "id" => division_id),
|
|
|
|
|
division,
|
|
|
|
|
iihf_team_stats_table: IihfTeamStatsTableTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
iihf_stats,
|
|
|
|
|
lang,
|
|
|
|
|
},
|
|
|
|
|
games,
|
|
|
|
|
lang,
|
|
|
|
@ -354,33 +365,30 @@ async fn score_for_game_html(
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
let score = game.score(&server_config.db_pool).await.unwrap();
|
|
|
|
|
let score_html = TeamGameStatsTemplate { locale: lang.into(), teams: score, lang };
|
|
|
|
|
let score_html = TeamGameStatsTemplate { locale: lang.into(), teams: score };
|
|
|
|
|
let goal_details = game.box_score(&server_config.db_pool)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
let goal_details_html = IndividualGamePointsTableTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
players: goal_details,
|
|
|
|
|
lang,
|
|
|
|
|
};
|
|
|
|
|
let box_score = game.goals(&server_config.db_pool).await.unwrap();
|
|
|
|
|
let box_score_html = BoxScoreTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
goals: box_score,
|
|
|
|
|
lang,
|
|
|
|
|
};
|
|
|
|
|
let pbp_html = ShotsTableTemplate { locale: lang.into(), shots: pbp, lang };
|
|
|
|
|
let pbp_html = ShotsTableTemplate { locale: lang.into(), shots: pbp };
|
|
|
|
|
let game_template = GameScorePageTemplate {
|
|
|
|
|
locale: lang.into(),
|
|
|
|
|
lang_links: lang.other_langs().map(move |olang| LangLink::from_lang_and_id(olang, game_id, "game_url_tmpl")).collect(),
|
|
|
|
|
url_name: "game_url_tmpl",
|
|
|
|
|
lang_links: other_lang_urls!(lang, GameScorePageTemplate, "id" => game_id),
|
|
|
|
|
division,
|
|
|
|
|
game,
|
|
|
|
|
lang,
|
|
|
|
|
box_score: box_score_html,
|
|
|
|
|
team_stats: score_html,
|
|
|
|
|
individual_stats: goal_details_html,
|
|
|
|
|
play_by_play: pbp_html,
|
|
|
|
|
lang,
|
|
|
|
|
};
|
|
|
|
|
(StatusCode::OK, game_template)
|
|
|
|
|
}
|
|
|
|
@ -397,7 +405,6 @@ macro_rules! insert {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_all_query_types {
|
|
|
|
|
($ty:ident, $func_all:ident, $func_by_id:ident) => {
|
|
|
|
@ -412,3 +419,4 @@ impl_all_query_types!(Team, team_all, team_id);
|
|
|
|
|
impl_all_query_types!(Shot, shots_all, shots_id);
|
|
|
|
|
impl_all_query_types!(Division, division_all, division_id);
|
|
|
|
|
impl_all_query_types!(League, league_all, league_id);
|
|
|
|
|
*/
|
|
|
|
|