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",
|
"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]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -71,6 +82,12 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-tzdata"
|
name = "android-tzdata"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -514,6 +531,18 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -744,6 +773,19 @@ name = "hashbrown"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
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]]
|
[[package]]
|
||||||
name = "headers"
|
name = "headers"
|
||||||
|
@ -952,6 +994,17 @@ version = "0.2.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
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]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -1021,6 +1074,7 @@ dependencies = [
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"futures",
|
"futures",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serenity",
|
"serenity",
|
||||||
|
@ -1516,6 +1570,20 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
|
|
|
@ -13,6 +13,7 @@ chrono = "0.4.23"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
futures = "0.3.26"
|
futures = "0.3.26"
|
||||||
reqwest = "0.11.14"
|
reqwest = "0.11.14"
|
||||||
|
rusqlite = { version = "0.29.0", features = ["bundled"] }
|
||||||
serde = "1.0.152"
|
serde = "1.0.152"
|
||||||
serde_json = "1.0.93"
|
serde_json = "1.0.93"
|
||||||
thiserror = "1.0.38"
|
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)]
|
#![feature(async_closure)]
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
mod db;
|
||||||
mod htmx;
|
mod htmx;
|
||||||
mod media;
|
mod media;
|
||||||
mod page;
|
mod page;
|
||||||
|
@ -128,6 +129,9 @@ fn spawn_api(settings: Arc<Mutex<Settings>>) {
|
||||||
let origin = env::var("APP_ORIGIN").expect("expected APP_ORIGIN");
|
let origin = env::var("APP_ORIGIN").expect("expected APP_ORIGIN");
|
||||||
|
|
||||||
let state = ApiState {
|
let state = ApiState {
|
||||||
|
db: Arc::new(tokio::sync::Mutex::new(
|
||||||
|
db::Database::new("db.sqlite").expect("couldn't open sqlite db"),
|
||||||
|
)),
|
||||||
settings,
|
settings,
|
||||||
secrets,
|
secrets,
|
||||||
origin: origin.clone(),
|
origin: origin.clone(),
|
||||||
|
|
28
src/page.rs
28
src/page.rs
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::{self, User},
|
auth::{self, User},
|
||||||
|
db,
|
||||||
htmx::{Build, HtmxBuilder, Tag},
|
htmx::{Build, HtmxBuilder, Tag},
|
||||||
settings::{ApiState, GuildSettings, Intro, IntroFriendlyName},
|
settings::{ApiState, GuildSettings, Intro, IntroFriendlyName},
|
||||||
};
|
};
|
||||||
|
@ -27,19 +28,20 @@ pub(crate) async fn home(
|
||||||
user: Option<User>,
|
user: Option<User>,
|
||||||
) -> Result<Html<String>, Redirect> {
|
) -> Result<Html<String>, Redirect> {
|
||||||
if let Some(user) = user {
|
if let Some(user) = user {
|
||||||
let settings = state.settings.lock().await;
|
let db = state.db.lock().await;
|
||||||
|
|
||||||
let guild = settings
|
let user_guilds = db.get_user_guilds(&user.name).map_err(|err| {
|
||||||
.guilds
|
error!(?err, "failed to get user guilds");
|
||||||
.iter()
|
// TODO: change this to returning a error to the client
|
||||||
.filter(|(_, guild_settings)| guild_settings.users.contains_key(&user.name));
|
Redirect::to("/login")
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Html(
|
Ok(Html(
|
||||||
page_header("MemeJoin - Home")
|
page_header("MemeJoin - Home")
|
||||||
.builder(Tag::Div, |b| {
|
.builder(Tag::Div, |b| {
|
||||||
b.attribute("class", "container")
|
b.attribute("class", "container")
|
||||||
.builder_text(Tag::Header2, "Choose a Guild")
|
.builder_text(Tag::Header2, "Choose a Guild")
|
||||||
.push_builder(guild_list(&state.origin, guild))
|
.push_builder(guild_list(&state.origin, user_guilds.iter()))
|
||||||
})
|
})
|
||||||
.build(),
|
.build(),
|
||||||
))
|
))
|
||||||
|
@ -48,22 +50,14 @@ pub(crate) async fn home(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guild_list<'a>(
|
fn guild_list<'a>(origin: &str, guilds: impl Iterator<Item = &'a db::Guild>) -> HtmxBuilder {
|
||||||
origin: &str,
|
|
||||||
guilds: impl Iterator<Item = (&'a u64, &'a GuildSettings)>,
|
|
||||||
) -> HtmxBuilder {
|
|
||||||
HtmxBuilder::new(Tag::Empty).ul(|b| {
|
HtmxBuilder::new(Tag::Empty).ul(|b| {
|
||||||
let mut b = b;
|
let mut b = b;
|
||||||
let mut in_any_guilds = false;
|
let mut in_any_guilds = false;
|
||||||
for (guild_id, guild_settings) in guilds {
|
for guild in guilds {
|
||||||
in_any_guilds = true;
|
in_any_guilds = true;
|
||||||
|
|
||||||
b = b.li(|b| {
|
b = b.li(|b| b.link(&guild.name, &format!("{}/guild/{}", origin, guild.id)));
|
||||||
b.link(
|
|
||||||
&guild_settings.name,
|
|
||||||
&format!("{}/guild/{}", origin, guild_id),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !in_any_guilds {
|
if !in_any_guilds {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{collections::HashMap, sync::Arc};
|
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::{async_trait, extract::FromRequestParts, http::request::Parts, response::Redirect};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -13,6 +13,7 @@ type UserToken = String;
|
||||||
// TODO: make this is wrapped type so cloning isn't happening
|
// TODO: make this is wrapped type so cloning isn't happening
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct ApiState {
|
pub(crate) struct ApiState {
|
||||||
|
pub db: Arc<tokio::sync::Mutex<Database>>,
|
||||||
pub settings: Arc<tokio::sync::Mutex<Settings>>,
|
pub settings: Arc<tokio::sync::Mutex<Settings>>,
|
||||||
pub secrets: auth::DiscordSecret,
|
pub secrets: auth::DiscordSecret,
|
||||||
pub origin: String,
|
pub origin: String,
|
||||||
|
|
Loading…
Reference in New Issue