get started with an actual database
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
parent
88ba532d1f
commit
969a97cab7
|
@ -62,6 +62,17 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.2"
|
||||
|
@ -71,6 +82,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
@ -514,6 +531,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.0"
|
||||
|
@ -744,6 +773,19 @@ name = "hashbrown"
|
|||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
|
@ -952,6 +994,17 @@ version = "0.2.147"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.3"
|
||||
|
@ -1021,6 +1074,7 @@ dependencies = [
|
|||
"dotenv",
|
||||
"futures",
|
||||
"reqwest",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serenity",
|
||||
|
@ -1516,6 +1570,20 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
|
|
|
@ -13,6 +13,7 @@ chrono = "0.4.23"
|
|||
dotenv = "0.15.0"
|
||||
futures = "0.3.26"
|
||||
reqwest = "0.11.14"
|
||||
rusqlite = { version = "0.29.0", features = ["bundled"] }
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.93"
|
||||
thiserror = "1.0.38"
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
use std::path::Path;
|
||||
|
||||
use rusqlite::{Connection, Result};
|
||||
|
||||
pub struct Database {
|
||||
conn: Connection,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
conn: Connection::open(path)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_user_guilds(&self, username: &str) -> Result<Vec<Guild>> {
|
||||
let mut query = self.conn.prepare(
|
||||
"
|
||||
SELECT
|
||||
id, name, sound_delay
|
||||
FROM Guild
|
||||
LEFT JOIN UserGuild ON UserGuild.guild_id = Guild.id
|
||||
WHERE UserGuild.username = :username
|
||||
",
|
||||
)?;
|
||||
|
||||
// NOTE(pcleavelin): for some reason this needs to be a let-binding or else
|
||||
// the compiler complains about it being dropped too early (maybe I should update the compiler version)
|
||||
let guilds = query
|
||||
.query_map(&[(":username", username)], |row| {
|
||||
Ok(Guild {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
sound_delay: row.get(2)?,
|
||||
})
|
||||
})?
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<Guild>>>();
|
||||
|
||||
guilds
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Guild {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub sound_delay: u32,
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(async_closure)]
|
||||
|
||||
mod auth;
|
||||
mod db;
|
||||
mod htmx;
|
||||
mod media;
|
||||
mod page;
|
||||
|
@ -128,6 +129,9 @@ fn spawn_api(settings: Arc<Mutex<Settings>>) {
|
|||
let origin = env::var("APP_ORIGIN").expect("expected APP_ORIGIN");
|
||||
|
||||
let state = ApiState {
|
||||
db: Arc::new(tokio::sync::Mutex::new(
|
||||
db::Database::new("db.sqlite").expect("couldn't open sqlite db"),
|
||||
)),
|
||||
settings,
|
||||
secrets,
|
||||
origin: origin.clone(),
|
||||
|
|
28
src/page.rs
28
src/page.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
auth::{self, User},
|
||||
db,
|
||||
htmx::{Build, HtmxBuilder, Tag},
|
||||
settings::{ApiState, GuildSettings, Intro, IntroFriendlyName},
|
||||
};
|
||||
|
@ -27,19 +28,20 @@ pub(crate) async fn home(
|
|||
user: Option<User>,
|
||||
) -> Result<Html<String>, Redirect> {
|
||||
if let Some(user) = user {
|
||||
let settings = state.settings.lock().await;
|
||||
let db = state.db.lock().await;
|
||||
|
||||
let guild = settings
|
||||
.guilds
|
||||
.iter()
|
||||
.filter(|(_, guild_settings)| guild_settings.users.contains_key(&user.name));
|
||||
let user_guilds = db.get_user_guilds(&user.name).map_err(|err| {
|
||||
error!(?err, "failed to get user guilds");
|
||||
// TODO: change this to returning a error to the client
|
||||
Redirect::to("/login")
|
||||
})?;
|
||||
|
||||
Ok(Html(
|
||||
page_header("MemeJoin - Home")
|
||||
.builder(Tag::Div, |b| {
|
||||
b.attribute("class", "container")
|
||||
.builder_text(Tag::Header2, "Choose a Guild")
|
||||
.push_builder(guild_list(&state.origin, guild))
|
||||
.push_builder(guild_list(&state.origin, user_guilds.iter()))
|
||||
})
|
||||
.build(),
|
||||
))
|
||||
|
@ -48,22 +50,14 @@ pub(crate) async fn home(
|
|||
}
|
||||
}
|
||||
|
||||
fn guild_list<'a>(
|
||||
origin: &str,
|
||||
guilds: impl Iterator<Item = (&'a u64, &'a GuildSettings)>,
|
||||
) -> HtmxBuilder {
|
||||
fn guild_list<'a>(origin: &str, guilds: impl Iterator<Item = &'a db::Guild>) -> HtmxBuilder {
|
||||
HtmxBuilder::new(Tag::Empty).ul(|b| {
|
||||
let mut b = b;
|
||||
let mut in_any_guilds = false;
|
||||
for (guild_id, guild_settings) in guilds {
|
||||
for guild in guilds {
|
||||
in_any_guilds = true;
|
||||
|
||||
b = b.li(|b| {
|
||||
b.link(
|
||||
&guild_settings.name,
|
||||
&format!("{}/guild/{}", origin, guild_id),
|
||||
)
|
||||
});
|
||||
b = b.li(|b| b.link(&guild.name, &format!("{}/guild/{}", origin, guild.id)));
|
||||
}
|
||||
|
||||
if !in_any_guilds {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::auth;
|
||||
use crate::{auth, db::Database};
|
||||
use axum::{async_trait, extract::FromRequestParts, http::request::Parts, response::Redirect};
|
||||
use axum_extra::extract::CookieJar;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -13,6 +13,7 @@ type UserToken = String;
|
|||
// TODO: make this is wrapped type so cloning isn't happening
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ApiState {
|
||||
pub db: Arc<tokio::sync::Mutex<Database>>,
|
||||
pub settings: Arc<tokio::sync::Mutex<Settings>>,
|
||||
pub secrets: auth::DiscordSecret,
|
||||
pub origin: String,
|
||||
|
|
Loading…
Reference in New Issue