sakgjiodfkg
This commit is contained in:
parent
d0e802d77c
commit
e50b31fc3f
12 changed files with 182 additions and 78 deletions
|
@ -159,11 +159,11 @@ impl WengLinRating {
|
||||||
log::debug!("Getting human score for: {rating:?}±{uncertainty:?}");
|
log::debug!("Getting human score for: {rating:?}±{uncertainty:?}");
|
||||||
let uncertain = self.0.rating - self.0.uncertainty;
|
let uncertain = self.0.rating - self.0.uncertainty;
|
||||||
log::trace!("Minimum score is: {uncertain:?}");
|
log::trace!("Minimum score is: {uncertain:?}");
|
||||||
let multiplied = uncertain * 100.0;
|
let multiplied = uncertain * 300.0 / 5.0;
|
||||||
log::trace!("Multiplied score is: {multiplied:?}");
|
log::trace!("Multiplied score is: {multiplied:?}");
|
||||||
let floored: f64 = multiplied.floor();
|
let ceiled: f64 = multiplied.ceil();
|
||||||
log::trace!("Floored score is: {floored:?}");
|
log::trace!("Ceiled score is: {ceiled:?}");
|
||||||
let converted: i64 = floored as i64;
|
let converted: i64 = ceiled as i64;
|
||||||
log::debug!("Human score for {rating:?}±{uncertainty:?} is {converted:?}");
|
log::debug!("Human score for {rating:?}±{uncertainty:?} is {converted:?}");
|
||||||
converted
|
converted
|
||||||
}
|
}
|
||||||
|
@ -231,6 +231,15 @@ impl Match {
|
||||||
.get_results::<Self>(conn)
|
.get_results::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn played_by(conn: &mut PgConnection, player_id: i32) -> QueryResult<Vec<Self>> {
|
||||||
|
schema::matches::table
|
||||||
|
.select(Self::as_select())
|
||||||
|
.or_filter(schema::matches::player_a_id.eq(player_id))
|
||||||
|
.or_filter(schema::matches::player_b_id.eq(player_id))
|
||||||
|
.order_by(schema::matches::instant.desc())
|
||||||
|
.get_results::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn played_by_count(conn: &mut PgConnection, player_id: i32) -> QueryResult<i64> {
|
pub fn played_by_count(conn: &mut PgConnection, player_id: i32) -> QueryResult<i64> {
|
||||||
schema::matches::table
|
schema::matches::table
|
||||||
.select(diesel::dsl::count_star())
|
.select(diesel::dsl::count_star())
|
||||||
|
|
|
@ -75,6 +75,9 @@ async fn main() -> anyhow::Result<Infallible> {
|
||||||
.route("/api/matches/",
|
.route("/api/matches/",
|
||||||
axum::routing::post(routes::matches::post_match)
|
axum::routing::post(routes::matches::post_match)
|
||||||
)
|
)
|
||||||
|
.route("/api/matches/holycow/:player_id",
|
||||||
|
axum::routing::post(routes::matches::get_played_by_id)
|
||||||
|
)
|
||||||
.nest("/telegram/webhook",
|
.nest("/telegram/webhook",
|
||||||
telegram_router
|
telegram_router
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::{Extension, Json};
|
use axum::{Extension, Json};
|
||||||
|
use axum::extract::Path;
|
||||||
use diesel::{Connection, PgConnection};
|
use diesel::{Connection, PgConnection};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use skillratings::weng_lin::WengLinConfig;
|
use skillratings::weng_lin::WengLinConfig;
|
||||||
|
@ -9,6 +10,14 @@ use teloxide::types::{ChatId, MessageId, ParseMode, ThreadId};
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::database::model::{Match, MatchI, Outcome, Player, WengLinRating};
|
use crate::database::model::{Match, MatchI, Outcome, Player, WengLinRating};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct MatchII {
|
||||||
|
name: Option<String>,
|
||||||
|
player_a: i32,
|
||||||
|
player_b: i32,
|
||||||
|
outcome: Outcome,
|
||||||
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
pub async fn get_all()
|
pub async fn get_all()
|
||||||
-> Result<Json<Vec<Match>>, StatusCode>
|
-> Result<Json<Vec<Match>>, StatusCode>
|
||||||
|
@ -22,29 +31,46 @@ pub async fn get_all()
|
||||||
Ok(Json(matches))
|
Ok(Json(matches))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[axum::debug_handler]
|
||||||
pub struct MatchII {
|
pub async fn get_played_by_id(
|
||||||
name: Option<String>,
|
Path(player_id): Path<i32>,
|
||||||
player_a: i32,
|
)
|
||||||
player_b: i32,
|
-> Result<Json<Vec<Match>>, StatusCode>
|
||||||
outcome: Outcome,
|
{
|
||||||
|
let mut conn = PgConnection::establish(config::DATABASE_URL())
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
let matches = Match::played_by(&mut conn, player_id)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
Ok(Json(matches))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn player_to_text(player: &Player, before: &WengLinRating, after: &WengLinRating) -> String {
|
fn player_to_text(player: &Player, before: &WengLinRating, after: &WengLinRating) -> String {
|
||||||
let name = &player.username;
|
let name = &player.username;
|
||||||
let competitive = &player.competitive;
|
let competitive = &player.competitive;
|
||||||
let telegram_id = &player.telegram_id;
|
let telegram_id = &player.telegram_id.clone().map(|t| t.0);
|
||||||
|
|
||||||
match competitive {
|
match competitive {
|
||||||
false => {
|
false => {
|
||||||
format!("{name}")
|
match telegram_id {
|
||||||
|
None =>
|
||||||
|
format!(r#"<b>{name}</b>"#),
|
||||||
|
Some(telegram_id) =>
|
||||||
|
format!(r#"<b><a href="tg://user?id={telegram_id}">{name}</a></b>"#),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
true => {
|
true => {
|
||||||
let before = before.human_score();
|
let before = before.human_score();
|
||||||
let after = after.human_score();
|
let after = after.human_score();
|
||||||
let change = after - before;
|
let change = after - before;
|
||||||
|
|
||||||
format!(r#"<b><a href="tg://user?id={telegram_id}">{name}</a></b> <i>({change:+})</i>"#)
|
match telegram_id {
|
||||||
|
None =>
|
||||||
|
format!(r#"<b>{name}</b> ({change:+} ★)"#),
|
||||||
|
Some(telegram_id) =>
|
||||||
|
format!(r#"<b><a href="tg://user?id={telegram_id}">{name}</a></b> ({change:+} ★)"#),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,22 @@ pub async fn get_all()
|
||||||
Ok(Json(players.into_iter().map(Into::into).collect()))
|
Ok(Json(players.into_iter().map(Into::into).collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is an awful hack but idc i'm out of time
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct PlayerOO {
|
||||||
|
id: i32,
|
||||||
|
telegram_id: Option<TelegramId>,
|
||||||
|
username: String,
|
||||||
|
human_score: Option<i64>,
|
||||||
|
played: i64,
|
||||||
|
wins: i64,
|
||||||
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
pub async fn get_by_id(
|
pub async fn get_by_id(
|
||||||
Path(player_id): Path<i32>,
|
Path(player_id): Path<i32>,
|
||||||
)
|
)
|
||||||
-> Result<Json<PlayerO>, StatusCode>
|
-> Result<Json<PlayerOO>, StatusCode>
|
||||||
{
|
{
|
||||||
let mut conn = PgConnection::establish(config::DATABASE_URL())
|
let mut conn = PgConnection::establish(config::DATABASE_URL())
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
@ -56,14 +67,29 @@ pub async fn get_by_id(
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
Ok(Json(player.into()))
|
let played = player.played_count(&mut conn)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
let wins = player.won_count(&mut conn)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
let player_o = PlayerO::from(player);
|
||||||
|
|
||||||
|
Ok(Json(PlayerOO {
|
||||||
|
id: player_o.id,
|
||||||
|
telegram_id: player_o.telegram_id,
|
||||||
|
username: player_o.username,
|
||||||
|
human_score: player_o.human_score,
|
||||||
|
played,
|
||||||
|
wins,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
pub async fn get_by_telegram_id(
|
pub async fn get_by_telegram_id(
|
||||||
Path(telegram_id): Path<TelegramId>,
|
Path(telegram_id): Path<TelegramId>,
|
||||||
)
|
)
|
||||||
-> Result<Json<PlayerO>, StatusCode>
|
-> Result<Json<PlayerOO>, StatusCode>
|
||||||
{
|
{
|
||||||
let mut conn = PgConnection::establish(config::DATABASE_URL())
|
let mut conn = PgConnection::establish(config::DATABASE_URL())
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
@ -72,5 +98,20 @@ pub async fn get_by_telegram_id(
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
Ok(Json(player.into()))
|
let played = player.played_count(&mut conn)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
let wins = player.won_count(&mut conn)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
let player_o = PlayerO::from(player);
|
||||||
|
|
||||||
|
Ok(Json(PlayerOO {
|
||||||
|
id: player_o.id,
|
||||||
|
telegram_id: player_o.telegram_id,
|
||||||
|
username: player_o.username,
|
||||||
|
human_score: player_o.human_score,
|
||||||
|
played,
|
||||||
|
wins,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
export default async function Page() {
|
import {ProfileBox} from "@/components/ProfileBox"
|
||||||
|
import {PlayerOO} from "@/holycow"
|
||||||
|
|
||||||
|
|
||||||
|
export default async function Page({params: {telegramId}}) {
|
||||||
|
const playerResponse = await fetch(`${process.env.BASE_URL}/api/results/telegram/${telegramId}`)
|
||||||
|
const player: PlayerOO = await playerResponse.json()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProfileBox
|
||||||
|
player={player}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
|
@ -18,3 +18,7 @@ hr {
|
||||||
/* TODO: Fix in bluelib */
|
/* TODO: Fix in bluelib */
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fof {
|
||||||
|
text-align: center;
|
||||||
|
}
|
|
@ -28,7 +28,13 @@ export default function RootLayout({ children }) {
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
Stagione 1
|
<span>
|
||||||
|
Stagione 1:
|
||||||
|
</span>
|
||||||
|
<br/>
|
||||||
|
<small>
|
||||||
|
Standard Brawl
|
||||||
|
</small>
|
||||||
</h2>
|
</h2>
|
||||||
</header>
|
</header>
|
||||||
<TelegramContext.Provider value={telegram}>
|
<TelegramContext.Provider value={telegram}>
|
||||||
|
@ -38,7 +44,9 @@ export default function RootLayout({ children }) {
|
||||||
<p>
|
<p>
|
||||||
© Stefano Pigozzi
|
© Stefano Pigozzi
|
||||||
-
|
-
|
||||||
che cursata, non ha senso, che cursata
|
Star Shard
|
||||||
|
-
|
||||||
|
che cursata le miniapp di telegram
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
19
holycow_frontend/src/app/none/page.tsx
Normal file
19
holycow_frontend/src/app/none/page.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import {ProfileBox} from "@/components/ProfileBox"
|
||||||
|
import {PlayerOO} from "@/holycow"
|
||||||
|
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
return (
|
||||||
|
<div className={"panel box fof"}>
|
||||||
|
<h3>
|
||||||
|
👍
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
hai scoperto la pagina di tutti i tempi
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
congrats!!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -14,8 +14,6 @@ export default function Page() {
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
switch(startParam) {
|
switch(startParam) {
|
||||||
case undefined:
|
|
||||||
return
|
|
||||||
case "profile":
|
case "profile":
|
||||||
router.replace(`/${data.user.id}/profile`)
|
router.replace(`/${data.user.id}/profile`)
|
||||||
return
|
return
|
||||||
|
@ -23,7 +21,7 @@ export default function Page() {
|
||||||
router.replace(`/${data.user.id}/report`)
|
router.replace(`/${data.user.id}/report`)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
router.replace(`/error404`)
|
router.replace(`/none`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -32,7 +30,7 @@ export default function Page() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoadingBox>
|
<LoadingBox>
|
||||||
Connecting to Telegram...
|
Connessione a Telegram in corso...
|
||||||
</LoadingBox>
|
</LoadingBox>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,81 +1,57 @@
|
||||||
import {StatPanel} from "@/components/StatPanel"
|
import {StatPanel} from "@/components/StatPanel"
|
||||||
|
import {PlayerOO} from "@/holycow"
|
||||||
import classNames from "classnames"
|
import classNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
export type ProfileBoxProps = {
|
export type ProfileBoxProps = {
|
||||||
userName: string,
|
player: PlayerOO
|
||||||
played: number,
|
|
||||||
won: number,
|
|
||||||
rating: number,
|
|
||||||
uncertainty: number,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function ProfileBox({userName, played, won, rating, uncertainty}: ProfileBoxProps) {
|
export function ProfileBox({player}: ProfileBoxProps) {
|
||||||
return (
|
return (
|
||||||
<div className={"chapter-1"}>
|
<div className={"chapter-1"}>
|
||||||
<div className={"panel box"}>
|
<div className={"panel box"}>
|
||||||
<h3>
|
<h3>
|
||||||
{userName}
|
{player.username}
|
||||||
</h3>
|
</h3>
|
||||||
<div className={"chapter-4"}>
|
<div className={"chapter-4"}>
|
||||||
<StatPanel
|
<StatPanel
|
||||||
name={"Giocate"}
|
name={"Giocate"}
|
||||||
value={(
|
|
||||||
<data
|
|
||||||
className={classNames({
|
className={classNames({
|
||||||
"fade": played === 0
|
"fade": player.played === 0
|
||||||
})}
|
})}
|
||||||
value={played}
|
value={(
|
||||||
>
|
<data value={player.played}>
|
||||||
{played}
|
{player.played}
|
||||||
</data>
|
</data>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<StatPanel
|
<StatPanel
|
||||||
name={"Vinte"}
|
name={"Vinte"}
|
||||||
value={(
|
|
||||||
<data
|
|
||||||
className={classNames({
|
className={classNames({
|
||||||
"fade": won === 0
|
"fade": player.wins === 0,
|
||||||
|
"green": player.wins !== 0,
|
||||||
})}
|
})}
|
||||||
value={won}
|
value={(
|
||||||
>
|
<data value={player.wins}>
|
||||||
{won}
|
{player.wins}
|
||||||
</data>
|
</data>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
{player.human_score !== null &&
|
||||||
<StatPanel
|
<StatPanel
|
||||||
name={"Punteggio"}
|
name={"★"}
|
||||||
|
className={"yellow"}
|
||||||
value={(
|
value={(
|
||||||
<span
|
|
||||||
className={classNames({
|
|
||||||
"fade": rating === 0
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{rating === 0
|
|
||||||
?
|
|
||||||
<>
|
|
||||||
<data value={rating}>
|
|
||||||
-
|
|
||||||
</data>
|
|
||||||
</>
|
|
||||||
:
|
|
||||||
<>
|
|
||||||
<data value={rating}>
|
|
||||||
{rating}
|
|
||||||
</data>
|
|
||||||
<span>
|
<span>
|
||||||
±
|
<data value={player.human_score}>
|
||||||
</span>
|
{player.human_score}
|
||||||
<data value={uncertainty}>
|
|
||||||
{uncertainty}
|
|
||||||
</data>
|
</data>
|
||||||
</>
|
|
||||||
}
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import style from "./StatPanel.module.css"
|
import style from "./StatPanel.module.css"
|
||||||
|
|
||||||
export function StatPanel({name, value, display = value}) {
|
export function StatPanel({className, name, value, display = value}) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames("panel", style.panel)}>
|
<div className={classNames("panel", style.panel, className)}>
|
||||||
<h4 className={style.name}>
|
<h4 className={style.name}>
|
||||||
{name}
|
{name}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
|
@ -10,3 +10,12 @@ export type PlayerO = {
|
||||||
username: string,
|
username: string,
|
||||||
human_score: null | number,
|
human_score: null | number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PlayerOO = {
|
||||||
|
id: number,
|
||||||
|
telegram_id: number,
|
||||||
|
username: string,
|
||||||
|
human_score: null | number,
|
||||||
|
played: number,
|
||||||
|
wins: number,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue