Some minor restructuring and improvements
This commit is contained in:
96
Cargo.lock
generated
96
Cargo.lock
generated
@@ -152,6 +152,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"common",
|
||||
"diesel",
|
||||
"diesel-async",
|
||||
"diesel_async_migrations",
|
||||
@@ -287,6 +288,13 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.14.0"
|
||||
@@ -631,8 +639,11 @@ dependencies = [
|
||||
name = "frontend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"leptos",
|
||||
"leptos_router",
|
||||
"reqwasm",
|
||||
"stylers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1235,6 +1246,32 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5006e35b7c768905286dbea0d3525396cd39d961cb7b9fb664aa00b0c984ae6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"gloo-net 0.6.0",
|
||||
"itertools",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"leptos",
|
||||
"linear-map",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_qs 0.13.0",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leptos_server"
|
||||
version = "0.6.14"
|
||||
@@ -1251,18 +1288,43 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "linear-map"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
@@ -2071,6 +2133,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_qs"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.7"
|
||||
@@ -2080,6 +2153,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_test"
|
||||
version = "1.0.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -2110,7 +2192,7 @@ dependencies = [
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_qs",
|
||||
"serde_qs 0.12.0",
|
||||
"server_fn_macro_default",
|
||||
"thiserror",
|
||||
"url",
|
||||
@@ -2249,6 +2331,18 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "stylers"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e306edf4b3cb5cff4b2e21b8895ed9e70fbd1bbb3a8dfb7e4cc245a763a955"
|
||||
dependencies = [
|
||||
"levenshtein",
|
||||
"litrs",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[workspace]
|
||||
members = ["backend", "frontend"]
|
||||
members = ["backend", "common", "frontend"]
|
||||
resolver = "2"
|
||||
|
||||
@@ -20,3 +20,5 @@ diesel = { version = "2.2", features = ["serde_json"] }
|
||||
diesel-async = { version = "0.5", features = ["postgres"] }
|
||||
serde_json = "1.0.128"
|
||||
diesel_async_migrations = { version = "0.15" }
|
||||
|
||||
common = { path = "../common/" }
|
||||
|
||||
115
backend/src/api.rs
Normal file
115
backend/src/api.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
pub mod demos {
|
||||
use crate::UserSession;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use diesel::prelude::*;
|
||||
use axum::extract::{State, Path};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct DemoState {
|
||||
upload_folder: std::path::PathBuf,
|
||||
}
|
||||
|
||||
pub fn router<P>(upload_folder: P) -> axum::Router where P: Into<std::path::PathBuf> {
|
||||
axum::Router::new()
|
||||
.route("/list", axum::routing::get(list))
|
||||
.route("/upload", axum::routing::post(upload).layer(axum::extract::DefaultBodyLimit::max(500*1024*1024)))
|
||||
.route("/:id/info", axum::routing::get(info))
|
||||
.with_state(Arc::new(DemoState {
|
||||
upload_folder: upload_folder.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
async fn list(session: UserSession) -> Result<axum::response::Json<Vec<common::BaseDemoInfo>>, axum::http::StatusCode> {
|
||||
let steam_id = session.data().steam_id.ok_or_else(|| axum::http::StatusCode::UNAUTHORIZED)?;
|
||||
tracing::info!("SteamID: {:?}", steam_id);
|
||||
|
||||
let query = crate::schema::demos::dsl::demos.filter(crate::schema::demos::dsl::steam_id.eq(steam_id as i64));
|
||||
let results: Vec<crate::models::Demo> = query.load(&mut crate::db_connection().await).await.unwrap();
|
||||
|
||||
Ok(axum::response::Json(results.into_iter().map(|demo| common::BaseDemoInfo {
|
||||
id: demo.demo_id,
|
||||
}).collect::<Vec<_>>()))
|
||||
}
|
||||
|
||||
async fn upload(State(state): State<Arc<DemoState>>, session: crate::UserSession, form: axum::extract::Multipart) -> Result<axum::response::Redirect, (axum::http::StatusCode, &'static str)> {
|
||||
let steam_id = session.data().steam_id.ok_or_else(|| (axum::http::StatusCode::UNAUTHORIZED, "Not logged in"))?;
|
||||
|
||||
tracing::info!("Upload for Session: {:?}", steam_id);
|
||||
|
||||
let file_content = crate::get_demo_from_upload("demo", form).await.unwrap();
|
||||
|
||||
let user_folder = std::path::Path::new(&state.upload_folder).join(format!("{}/", steam_id));
|
||||
if !tokio::fs::try_exists(&user_folder).await.unwrap_or(false) {
|
||||
tokio::fs::create_dir_all(&user_folder).await.unwrap();
|
||||
}
|
||||
|
||||
let timestamp_secs = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||
let demo_file_path = user_folder.join(format!("{}.dem", timestamp_secs));
|
||||
|
||||
tokio::fs::write(demo_file_path, file_content).await.unwrap();
|
||||
|
||||
let query = diesel::dsl::insert_into(crate::schema::demos::dsl::demos).values(crate::models::Demo {
|
||||
demo_id: timestamp_secs as i64,
|
||||
steam_id: steam_id as i64,
|
||||
});
|
||||
query.execute(&mut crate::db_connection().await).await.unwrap();
|
||||
|
||||
Ok(axum::response::Redirect::to("/"))
|
||||
}
|
||||
|
||||
async fn info(session: UserSession, Path(demo_id): Path<i64>) -> Result<(), axum::http::StatusCode> {
|
||||
tracing::info!("Get info for Demo: {:?}", demo_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod steam {
|
||||
use axum::extract::State;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn router(url: &str, callback_path: &str) -> axum::Router {
|
||||
axum::Router::new()
|
||||
.route("/login", axum::routing::get(steam_login))
|
||||
.route("/callback", axum::routing::get(steam_callback))
|
||||
.with_state(Arc::new(steam_openid::SteamOpenId::new(url, callback_path).unwrap()))
|
||||
}
|
||||
|
||||
async fn steam_login(State(openid): State<Arc<steam_openid::SteamOpenId>>) -> Result<axum::response::Redirect, axum::http::StatusCode> {
|
||||
let url = openid.get_redirect_url();
|
||||
|
||||
Ok(axum::response::Redirect::to(url))
|
||||
}
|
||||
|
||||
async fn steam_callback(
|
||||
State(openid): State<Arc<steam_openid::SteamOpenId>>,
|
||||
mut session: crate::UserSession,
|
||||
request: axum::extract::Request,
|
||||
) -> Result<axum::response::Redirect, axum::http::StatusCode> {
|
||||
tracing::info!("Steam Callback");
|
||||
|
||||
let query = request.uri().query().ok_or_else(|| {
|
||||
tracing::error!("Missing query in parameters");
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
})?;
|
||||
|
||||
let id = openid.verify(query).await.map_err(|e| {
|
||||
tracing::error!("Verifying OpenID: {:?}", e);
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
})?;
|
||||
|
||||
session
|
||||
.modify_data(|data| {
|
||||
data.steam_id = Some(id);
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(axum::response::Redirect::to("/"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn router() -> axum::Router {
|
||||
axum::Router::new()
|
||||
.nest("/steam/", steam::router("http://192.168.0.156:3000", "/api/steam/callback"))
|
||||
.nest("/demos/", demos::router("uploads/"))
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod models;
|
||||
pub mod schema;
|
||||
|
||||
@@ -34,3 +32,5 @@ pub async fn get_demo_from_upload(name: &str, mut form: axum::extract::Multipart
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub mod api;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
|
||||
|
||||
use diesel::prelude::*;
|
||||
use diesel_async::{RunQueryDsl, AsyncConnection, AsyncPgConnection};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
static OPENID: std::sync::LazyLock<steam_openid::SteamOpenId> = std::sync::LazyLock::new(|| {
|
||||
steam_openid::SteamOpenId::new("http://192.168.0.156:3000", "/api/steam/callback").unwrap()
|
||||
});
|
||||
static UPLOAD_FOLDER: &str = "uploads/";
|
||||
|
||||
const MIGRATIONS: diesel_async_migrations::EmbeddedMigrations = diesel_async_migrations::embed_migrations!("../migrations/");
|
||||
@@ -33,7 +30,7 @@ async fn main() {
|
||||
let session_layer = tower_sessions::SessionManagerLayer::new(session_store)
|
||||
.with_secure(false)
|
||||
.with_expiry(tower_sessions::Expiry::OnInactivity(
|
||||
time::Duration::minutes(15),
|
||||
time::Duration::hours(48),
|
||||
));
|
||||
|
||||
if !tokio::fs::try_exists(UPLOAD_FOLDER).await.unwrap_or(false) {
|
||||
@@ -41,14 +38,7 @@ async fn main() {
|
||||
}
|
||||
|
||||
let router = axum::Router::new()
|
||||
.nest_service(
|
||||
"/api/",
|
||||
axum::Router::new()
|
||||
.route("/steam/callback", axum::routing::get(steam_callback))
|
||||
.route("/steam/login", axum::routing::get(steam_login))
|
||||
.route("/demos/upload", axum::routing::post(upload).layer(axum::extract::DefaultBodyLimit::max(1024*1024*500)))
|
||||
.route("/demos/list", axum::routing::get(demos_list))
|
||||
)
|
||||
.nest("/api/", backend::api::router())
|
||||
.layer(session_layer)
|
||||
.nest_service("/", tower_http::services::ServeDir::new("frontend/dist/"));
|
||||
|
||||
@@ -56,71 +46,6 @@ async fn main() {
|
||||
axum::serve(listener, router).await.unwrap();
|
||||
}
|
||||
|
||||
async fn upload(session: backend::UserSession, form: axum::extract::Multipart) -> Result<axum::response::Redirect, (axum::http::StatusCode, &'static str)> {
|
||||
let steam_id = session.data().steam_id.ok_or_else(|| (axum::http::StatusCode::UNAUTHORIZED, "Not logged in"))?;
|
||||
|
||||
tracing::info!("Upload for Session: {:?}", steam_id);
|
||||
|
||||
let file_content = backend::get_demo_from_upload("demo", form).await.unwrap();
|
||||
|
||||
let user_folder = std::path::Path::new(UPLOAD_FOLDER).join(format!("{}/", steam_id));
|
||||
if !tokio::fs::try_exists(&user_folder).await.unwrap_or(false) {
|
||||
tokio::fs::create_dir_all(&user_folder).await.unwrap();
|
||||
}
|
||||
|
||||
let timestamp_secs = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||
let demo_file_path = user_folder.join(format!("{}.dem", timestamp_secs));
|
||||
|
||||
tokio::fs::write(demo_file_path, file_content).await.unwrap();
|
||||
|
||||
let query = diesel::dsl::insert_into(backend::schema::demos::dsl::demos).values(backend::models::Demo {
|
||||
demo_id: timestamp_secs as i64,
|
||||
steam_id: steam_id as i64,
|
||||
});
|
||||
query.execute(&mut backend::db_connection().await).await.unwrap();
|
||||
|
||||
Ok(axum::response::Redirect::to("/"))
|
||||
}
|
||||
|
||||
async fn steam_login() -> Result<axum::response::Redirect, axum::http::StatusCode> {
|
||||
let url = OPENID.get_redirect_url();
|
||||
|
||||
Ok(axum::response::Redirect::to(url))
|
||||
}
|
||||
|
||||
async fn steam_callback(
|
||||
mut session: backend::UserSession,
|
||||
request: axum::extract::Request,
|
||||
) -> Result<axum::response::Redirect, axum::http::StatusCode> {
|
||||
tracing::info!("Steam Callback");
|
||||
|
||||
let query = request.uri().query().ok_or_else(|| {
|
||||
tracing::error!("Missing query in parameters");
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
})?;
|
||||
|
||||
let id = OPENID.verify(query).await.map_err(|e| {
|
||||
tracing::error!("Verifying OpenID: {:?}", e);
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
})?;
|
||||
|
||||
session
|
||||
.modify_data(|data| {
|
||||
data.steam_id = Some(id);
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(axum::response::Redirect::to("/"))
|
||||
}
|
||||
|
||||
async fn demos_list(session: backend::UserSession) -> Result<(), axum::http::StatusCode> {
|
||||
let steam_id = session.data().steam_id.ok_or_else(|| axum::http::StatusCode::UNAUTHORIZED)?;
|
||||
tracing::info!("SteamID: {:?}", steam_id);
|
||||
|
||||
let query = backend::schema::demos::dsl::demos.filter(backend::schema::demos::dsl::steam_id.eq(steam_id as i64));
|
||||
let results: Vec<backend::models::Demo> = query.load(&mut backend::db_connection().await).await.unwrap();
|
||||
|
||||
dbg!(&results);
|
||||
|
||||
async fn demo_info(session: backend::UserSession) -> Result<(), axum::http::StatusCode> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
use diesel::prelude::*;
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub struct UserSessionData {
|
||||
pub steam_id: Option<u64>,
|
||||
|
||||
7
common/Cargo.toml
Normal file
7
common/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
4
common/src/lib.rs
Normal file
4
common/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct BaseDemoInfo {
|
||||
pub id: i64,
|
||||
}
|
||||
@@ -5,4 +5,8 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { version = "0.6", features = ["csr", "nightly"] }
|
||||
leptos_router = { version = "0.6", features = ["csr"] }
|
||||
reqwasm = "0.5.0"
|
||||
stylers = { version = "0.3" }
|
||||
|
||||
common = { path = "../common/" }
|
||||
|
||||
4
frontend/Trunk.toml
Normal file
4
frontend/Trunk.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[[hooks]]
|
||||
stage = "post_build"
|
||||
command = "sh"
|
||||
command_arguments = ["-c", "cp ../target/stylers/main.css $TRUNK_STAGING_DIR/"]
|
||||
@@ -1,5 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<head>
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
17
frontend/src/demo.rs
Normal file
17
frontend/src/demo.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use leptos::*;
|
||||
|
||||
#[leptos::component]
|
||||
pub fn demo() -> impl leptos::IntoView {
|
||||
let params = leptos_router::use_params_map();
|
||||
let id = move || params.with(|params| params.get("id").cloned().unwrap_or_default());
|
||||
|
||||
let demo_info = create_resource(|| (), move |_| async move {
|
||||
let res = reqwasm::http::Request::get(&format!("/api/demos/{}/info", id())).send().await.unwrap();
|
||||
dbg!(res.text().await);
|
||||
0
|
||||
});
|
||||
|
||||
view! {
|
||||
<h2>Demo - {id}</h2>
|
||||
}
|
||||
}
|
||||
107
frontend/src/lib.rs
Normal file
107
frontend/src/lib.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use leptos::*;
|
||||
use leptos_router::A;
|
||||
|
||||
mod demo;
|
||||
pub use demo::Demo;
|
||||
|
||||
#[leptos::component]
|
||||
pub fn demo_list_entry(demo: common::BaseDemoInfo) -> impl leptos::IntoView {
|
||||
view! {
|
||||
<li>
|
||||
<A href=format!("/demo/{}", demo.id)>Demo: {demo.id}</A>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
#[leptos::component]
|
||||
pub fn steam_login(height: &'static str, width: &'static str) -> impl leptos::IntoView {
|
||||
view! {
|
||||
<a href="/api/steam/login">
|
||||
<img src="https://community.akamai.steamstatic.com/public/images/signinthroughsteam/sits_01.png" alt="Steam Login" style=format!("height: {height}; width: {width}") />
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
#[leptos::component]
|
||||
pub fn upload_demo() -> impl leptos::IntoView {
|
||||
use leptos_router::Form;
|
||||
|
||||
view! {
|
||||
<div>
|
||||
<Form action="/api/demos/upload" method="post" enctype="multipart/form-data".to_string()>
|
||||
<p> Select File to upload </p>
|
||||
<input type="file" name="demo" id="demo"></input>
|
||||
<input type="submit" value="Upload Image" name="submit"></input>
|
||||
</Form>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[leptos::component]
|
||||
pub fn top_bar() -> impl leptos::IntoView {
|
||||
let style = stylers::style! {
|
||||
"TopBar",
|
||||
.bar {
|
||||
width: 100%;
|
||||
height: 4vh;
|
||||
padding-top: 0.5vh;
|
||||
padding-bottom: 0.5vh;
|
||||
|
||||
background-color: #28282f;
|
||||
color: #d5d5d5;
|
||||
}
|
||||
|
||||
.group {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.elem {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: #d5d5d5;
|
||||
}
|
||||
};
|
||||
|
||||
view! {class = style,
|
||||
<div class="bar">
|
||||
<A href="/" class="group">
|
||||
<p class="logo">Knifer</p>
|
||||
</A>
|
||||
|
||||
<div class="group" style="float: right">
|
||||
<div class="elem">
|
||||
Upload Demo
|
||||
</div>
|
||||
|
||||
<div class="elem">
|
||||
<SteamLogin height="4vh" width="auto" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[leptos::component]
|
||||
pub fn homepage() -> impl leptos::IntoView {
|
||||
let demo_data = create_resource(|| (), |_| async move {
|
||||
let res = reqwasm::http::Request::get("/api/demos/list").send().await.unwrap();
|
||||
let demos: Vec<common::BaseDemoInfo> = res.json().await.unwrap();
|
||||
demos
|
||||
});
|
||||
|
||||
view! {
|
||||
<div>
|
||||
<div>
|
||||
<h2>Demos</h2>
|
||||
<UploadDemo />
|
||||
</div>
|
||||
<ul>
|
||||
{ move || demo_data.get().unwrap_or_default().into_iter().map(|demo| crate::DemoListEntry(DemoListEntryProps {
|
||||
demo
|
||||
})).collect::<Vec<_>>() }
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
use leptos::*;
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::*;
|
||||
|
||||
async fn load_demos() -> usize {
|
||||
use frontend::{UploadDemo, TopBar, Homepage, Demo};
|
||||
|
||||
async fn load_demos() -> Vec<common::BaseDemoInfo> {
|
||||
let res = reqwasm::http::Request::get("/api/demos/list").send().await.unwrap();
|
||||
dbg!(res);
|
||||
let demos: Vec<common::BaseDemoInfo> = res.json().await.unwrap();
|
||||
|
||||
0
|
||||
demos
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -14,16 +16,16 @@ fn main() {
|
||||
});
|
||||
|
||||
mount_to_body(move || view! {
|
||||
<p>"Hello, world!"</p>
|
||||
<a href="/api/steam/login">Steam Login</a> { move || match async_data.get() {
|
||||
None => 123,
|
||||
Some(v) => v,
|
||||
} }
|
||||
|
||||
<form action="/api/demos/upload" method="post" enctype="multipart/form-data">
|
||||
Select File to upload
|
||||
<input type="file" name="demo" id="demo"></input>
|
||||
<input type="submit" value="Upload Image" name="submit"></input>
|
||||
</form>
|
||||
<Router>
|
||||
<nav>
|
||||
<TopBar />
|
||||
</nav>
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/" view=Homepage />
|
||||
<Route path="/demo/:id" view=Demo />
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
-- Your SQL goes here
|
||||
CREATE TABLE IF NOT EXISTS demos (
|
||||
steam_id bigint PRIMARY KEY,
|
||||
demo_id bigint
|
||||
steam_id bigint,
|
||||
demo_id bigint,
|
||||
PRIMARY KEY(steam_id, demo_id)
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
demos (steam_id) {
|
||||
demos (steam_id, demo_id) {
|
||||
steam_id -> Int8,
|
||||
demo_id -> Nullable<Int8>,
|
||||
demo_id -> Int8,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user