summaryrefslogtreecommitdiff
path: root/src/login/repo/auth.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-09-15 23:50:41 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-09-16 11:03:22 -0400
commit491cb3eb34d20140aed80dbb9edc39c4db5335d2 (patch)
treee1e2e009f064dc6dfc8c98d2bf97d8d1f7b45615 /src/login/repo/auth.rs
parent99b33023332393e46f5a661901b980b78e6fb133 (diff)
Consolidate most repository types into a repo module.
Having them contained in the individual endpoint groups conveyed an unintended sense that their intended scope was _only_ that endpoint group. It also made most repo-related import paths _quite_ long. This splits up the repos as follows: * "General applicability" repos - those that are only loosely connected to a single task, and are likely to be shared between tasks - go in crate::repo. * Specialized repos - those tightly connected to a specific task - go in the module for that task, under crate::PATH::repo. In both cases, each repo goes in its own submodule, to make it easier to use the module name as a namespace. Which category a repo goes in is a judgment call. `crate::channel::repo::broadcast` (formerly `channel::repo::messages`) is used outside of `crate::channel`, for example, but its main purpose is to support channel message broadcasts. It could arguably live under `crate::event::repo::channel`, but the resulting namespace is less legible to me.
Diffstat (limited to 'src/login/repo/auth.rs')
-rw-r--r--src/login/repo/auth.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/login/repo/auth.rs b/src/login/repo/auth.rs
new file mode 100644
index 0000000..78b44f0
--- /dev/null
+++ b/src/login/repo/auth.rs
@@ -0,0 +1,53 @@
+use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+
+use crate::{
+ password::StoredHash,
+ repo::login::{self, Login},
+};
+
+pub trait Provider {
+ fn auth(&mut self) -> Auth;
+}
+
+impl<'c> Provider for Transaction<'c, Sqlite> {
+ fn auth(&mut self) -> Auth {
+ Auth(self)
+ }
+}
+
+pub struct Auth<'t>(&'t mut SqliteConnection);
+
+impl<'t> Auth<'t> {
+ /// Retrieves a login by name, plus its stored password hash for
+ /// verification. If there's no login with the requested name, this will
+ /// return [None].
+ pub async fn for_name(
+ &mut self,
+ name: &str,
+ ) -> Result<Option<(Login, StoredHash)>, sqlx::Error> {
+ let found = sqlx::query!(
+ r#"
+ select
+ id as "id: login::Id",
+ name,
+ password_hash as "password_hash: StoredHash"
+ from login
+ where name = $1
+ "#,
+ name,
+ )
+ .map(|rec| {
+ (
+ Login {
+ id: rec.id,
+ name: rec.name,
+ },
+ rec.password_hash,
+ )
+ })
+ .fetch_optional(&mut *self.0)
+ .await?;
+
+ Ok(found)
+ }
+}