diff options
Diffstat (limited to 'src')
31 files changed, 284 insertions, 83 deletions
diff --git a/src/channel/app.rs b/src/channel/app.rs index 75c662d..ea60943 100644 --- a/src/channel/app.rs +++ b/src/channel/app.rs @@ -2,7 +2,7 @@ use chrono::TimeDelta; use itertools::Itertools; use sqlx::sqlite::SqlitePool; -use super::{repo::Provider as _, Channel, History, Id}; +use super::{repo::Provider as _, Channel, History, Id, Name}; use crate::{ clock::DateTime, db::{Duplicate as _, NotFound as _}, @@ -20,14 +20,14 @@ impl<'a> Channels<'a> { Self { db, events } } - pub async fn create(&self, name: &str, created_at: &DateTime) -> Result<Channel, CreateError> { + pub async fn create(&self, name: &Name, created_at: &DateTime) -> Result<Channel, CreateError> { let mut tx = self.db.begin().await?; let created = tx.sequence().next(created_at).await?; let channel = tx .channels() .create(name, &created) .await - .duplicate(|| CreateError::DuplicateName(name.into()))?; + .duplicate(|| CreateError::DuplicateName(name.clone()))?; tx.commit().await?; self.events @@ -134,7 +134,7 @@ impl<'a> Channels<'a> { #[derive(Debug, thiserror::Error)] pub enum CreateError { #[error("channel named {0} already exists")] - DuplicateName(String), + DuplicateName(Name), #[error(transparent)] Database(#[from] sqlx::Error), } diff --git a/src/channel/mod.rs b/src/channel/mod.rs index eb8200b..fb13e92 100644 --- a/src/channel/mod.rs +++ b/src/channel/mod.rs @@ -2,8 +2,11 @@ pub mod app; pub mod event; mod history; mod id; +mod name; pub mod repo; mod routes; mod snapshot; -pub use self::{event::Event, history::History, id::Id, routes::router, snapshot::Channel}; +pub use self::{ + event::Event, history::History, id::Id, name::Name, routes::router, snapshot::Channel, +}; diff --git a/src/channel/name.rs b/src/channel/name.rs new file mode 100644 index 0000000..fc82dec --- /dev/null +++ b/src/channel/name.rs @@ -0,0 +1,30 @@ +use std::fmt; + +use crate::nfc; + +#[derive( + Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, sqlx::Type, +)] +#[serde(transparent)] +#[sqlx(transparent)] +pub struct Name(nfc::String); + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(name) = self; + name.fmt(f) + } +} + +impl From<String> for Name { + fn from(name: String) -> Self { + Self(name.into()) + } +} + +impl From<Name> for String { + fn from(name: Name) -> Self { + let Name(name) = name; + name.into() + } +} diff --git a/src/channel/repo.rs b/src/channel/repo.rs index 27d35f0..3353bfd 100644 --- a/src/channel/repo.rs +++ b/src/channel/repo.rs @@ -1,7 +1,7 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use crate::{ - channel::{Channel, History, Id}, + channel::{Channel, History, Id, Name}, clock::DateTime, event::{Instant, ResumePoint, Sequence}, }; @@ -19,7 +19,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> { pub struct Channels<'t>(&'t mut SqliteConnection); impl<'c> Channels<'c> { - pub async fn create(&mut self, name: &str, created: &Instant) -> Result<History, sqlx::Error> { + pub async fn create(&mut self, name: &Name, created: &Instant) -> Result<History, sqlx::Error> { let id = Id::generate(); let channel = sqlx::query!( r#" @@ -28,7 +28,7 @@ impl<'c> Channels<'c> { values ($1, $2, $3, $4) returning id as "id: Id", - name as "name!", -- known non-null as we just set it + name as "name!: Name", -- known non-null as we just set it created_at as "created_at: DateTime", created_sequence as "created_sequence: Sequence" "#, @@ -57,7 +57,7 @@ impl<'c> Channels<'c> { r#" select id as "id: Id", - channel.name, + channel.name as "name: Name", channel.created_at as "created_at: DateTime", channel.created_sequence as "created_sequence: Sequence", deleted.deleted_at as "deleted_at?: DateTime", @@ -89,7 +89,7 @@ impl<'c> Channels<'c> { r#" select id as "id: Id", - channel.name, + channel.name as "name: Name", channel.created_at as "created_at: DateTime", channel.created_sequence as "created_sequence: Sequence", deleted.deleted_at as "deleted_at: DateTime", @@ -125,7 +125,7 @@ impl<'c> Channels<'c> { r#" select id as "id: Id", - channel.name, + channel.name as "name: Name", channel.created_at as "created_at: DateTime", channel.created_sequence as "created_sequence: Sequence", deleted.deleted_at as "deleted_at: DateTime", @@ -235,7 +235,7 @@ impl<'c> Channels<'c> { r#" select channel.id as "id: Id", - channel.name, + channel.name as "name: Name", channel.created_at as "created_at: DateTime", channel.created_sequence as "created_sequence: Sequence", deleted.deleted_at as "deleted_at?: DateTime", diff --git a/src/channel/routes/channel/post.rs b/src/channel/routes/channel/post.rs index b489a77..d0cae05 100644 --- a/src/channel/routes/channel/post.rs +++ b/src/channel/routes/channel/post.rs @@ -9,7 +9,7 @@ use crate::{ clock::RequestedAt, error::{Internal, NotFound}, login::Login, - message::{app::SendError, Message}, + message::{app::SendError, Body, Message}, }; pub async fn handler( @@ -29,7 +29,7 @@ pub async fn handler( #[derive(serde::Deserialize)] pub struct Request { - pub body: String, + pub body: Body, } #[derive(Debug)] diff --git a/src/channel/routes/post.rs b/src/channel/routes/post.rs index a05c312..d354f79 100644 --- a/src/channel/routes/post.rs +++ b/src/channel/routes/post.rs @@ -6,7 +6,7 @@ use axum::{ use crate::{ app::App, - channel::{app, Channel}, + channel::{app, Channel, Name}, clock::RequestedAt, error::Internal, login::Login, @@ -29,7 +29,7 @@ pub async fn handler( #[derive(serde::Deserialize)] pub struct Request { - pub name: String, + pub name: Name, } #[derive(Debug)] diff --git a/src/channel/snapshot.rs b/src/channel/snapshot.rs index 2b7d89a..dc2894d 100644 --- a/src/channel/snapshot.rs +++ b/src/channel/snapshot.rs @@ -1,13 +1,13 @@ use super::{ event::{Created, Event}, - Id, + Id, Name, }; use crate::clock::DateTime; #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct Channel { pub id: Id, - pub name: String, + pub name: Name, #[serde(skip_serializing_if = "Option::is_none")] pub deleted_at: Option<DateTime>, } diff --git a/src/invite/app.rs b/src/invite/app.rs index ee7f74f..285a819 100644 --- a/src/invite/app.rs +++ b/src/invite/app.rs @@ -6,7 +6,7 @@ use crate::{ clock::DateTime, db::{Duplicate as _, NotFound as _}, event::repo::Provider as _, - login::{repo::Provider as _, Login, Password}, + login::{repo::Provider as _, Login, Name, Password}, token::{repo::Provider as _, Secret}, }; @@ -42,7 +42,7 @@ impl<'a> Invites<'a> { pub async fn accept( &self, invite: &Id, - name: &str, + name: &Name, password: &Password, accepted_at: &DateTime, ) -> Result<(Login, Secret), AcceptError> { @@ -68,7 +68,7 @@ impl<'a> Invites<'a> { .logins() .create(name, &password_hash, &created) .await - .duplicate(|| AcceptError::DuplicateLogin(name.into()))?; + .duplicate(|| AcceptError::DuplicateLogin(name.clone()))?; let secret = tx.tokens().issue(&login, accepted_at).await?; tx.commit().await?; @@ -92,7 +92,7 @@ pub enum AcceptError { #[error("invite not found: {0}")] NotFound(Id), #[error("name in use: {0}")] - DuplicateLogin(String), + DuplicateLogin(Name), #[error(transparent)] Database(#[from] sqlx::Error), #[error(transparent)] diff --git a/src/invite/routes/invite/post.rs b/src/invite/routes/invite/post.rs index c072929..8160465 100644 --- a/src/invite/routes/invite/post.rs +++ b/src/invite/routes/invite/post.rs @@ -9,7 +9,7 @@ use crate::{ clock::RequestedAt, error::{Internal, NotFound}, invite::app, - login::{Login, Password}, + login::{Login, Name, Password}, token::extract::IdentityToken, }; @@ -31,7 +31,7 @@ pub async fn handler( #[derive(serde::Deserialize)] pub struct Request { - pub name: String, + pub name: Name, pub password: Password, } @@ -16,6 +16,7 @@ mod id; mod invite; mod login; mod message; +mod nfc; mod setup; #[cfg(test)] mod test; diff --git a/src/login/app.rs b/src/login/app.rs index b6f7e1c..ebc1c00 100644 --- a/src/login/app.rs +++ b/src/login/app.rs @@ -1,6 +1,6 @@ use sqlx::sqlite::SqlitePool; -use super::{repo::Provider as _, Login, Password}; +use super::{repo::Provider as _, Login, Name, Password}; use crate::{ clock::DateTime, event::{repo::Provider as _, Broadcaster, Event}, @@ -18,7 +18,7 @@ impl<'a> Logins<'a> { pub async fn create( &self, - name: &str, + name: &Name, password: &Password, created_at: &DateTime, ) -> Result<Login, CreateError> { diff --git a/src/login/mod.rs b/src/login/mod.rs index 98cc3d7..71d5bfc 100644 --- a/src/login/mod.rs +++ b/src/login/mod.rs @@ -4,11 +4,13 @@ pub mod event; pub mod extract; mod history; mod id; +mod name; pub mod password; pub mod repo; mod routes; mod snapshot; pub use self::{ - event::Event, history::History, id::Id, password::Password, routes::router, snapshot::Login, + event::Event, history::History, id::Id, name::Name, password::Password, routes::router, + snapshot::Login, }; diff --git a/src/login/name.rs b/src/login/name.rs new file mode 100644 index 0000000..d882ff9 --- /dev/null +++ b/src/login/name.rs @@ -0,0 +1,28 @@ +use std::fmt; + +use crate::nfc; + +#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, sqlx::Type)] +#[serde(transparent)] +#[sqlx(transparent)] +pub struct Name(nfc::String); + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(name) = self; + name.fmt(f) + } +} + +impl From<String> for Name { + fn from(name: String) -> Self { + Self(name.into()) + } +} + +impl From<Name> for String { + fn from(name: Name) -> Self { + let Name(name) = name; + name.into() + } +} diff --git a/src/login/password.rs b/src/login/password.rs index 14fd981..f9ecf37 100644 --- a/src/login/password.rs +++ b/src/login/password.rs @@ -4,6 +4,8 @@ use argon2::Argon2; use password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString}; use rand_core::OsRng; +use crate::nfc; + #[derive(sqlx::Type)] #[sqlx(transparent)] pub struct StoredHash(String); @@ -31,7 +33,7 @@ impl fmt::Debug for StoredHash { #[derive(serde::Deserialize)] #[serde(transparent)] -pub struct Password(String); +pub struct Password(nfc::String); impl Password { pub fn hash(&self) -> Result<StoredHash, password_hash::Error> { @@ -56,9 +58,8 @@ impl fmt::Debug for Password { } } -#[cfg(test)] impl From<String> for Password { fn from(password: String) -> Self { - Self(password) + Password(password.into()) } } diff --git a/src/login/repo.rs b/src/login/repo.rs index 7d0fcb1..204329f 100644 --- a/src/login/repo.rs +++ b/src/login/repo.rs @@ -3,7 +3,7 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use crate::{ clock::DateTime, event::{Instant, ResumePoint, Sequence}, - login::{password::StoredHash, History, Id, Login}, + login::{password::StoredHash, History, Id, Login, Name}, }; pub trait Provider { @@ -21,7 +21,7 @@ pub struct Logins<'t>(&'t mut SqliteConnection); impl<'c> Logins<'c> { pub async fn create( &mut self, - name: &str, + name: &Name, password_hash: &StoredHash, created: &Instant, ) -> Result<History, sqlx::Error> { @@ -34,7 +34,7 @@ impl<'c> Logins<'c> { values ($1, $2, $3, $4, $5) returning id as "id: Id", - name, + name as "name: Name", created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" "#, @@ -62,7 +62,7 @@ impl<'c> Logins<'c> { r#" select id as "id: Id", - name, + name as "name: Name", created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" from login @@ -88,7 +88,7 @@ impl<'c> Logins<'c> { r#" select id as "id: Id", - name, + name as "name: Name", created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" from login diff --git a/src/login/routes/login/post.rs b/src/login/routes/login/post.rs index 67eaa6d..7a685e2 100644 --- a/src/login/routes/login/post.rs +++ b/src/login/routes/login/post.rs @@ -8,7 +8,7 @@ use crate::{ app::App, clock::RequestedAt, error::Internal, - login::{Login, Password}, + login::{Login, Name, Password}, token::{app, extract::IdentityToken}, }; @@ -29,7 +29,7 @@ pub async fn handler( #[derive(serde::Deserialize)] pub struct Request { - pub name: String, + pub name: Name, pub password: Password, } diff --git a/src/login/snapshot.rs b/src/login/snapshot.rs index 1a92f5c..85800e4 100644 --- a/src/login/snapshot.rs +++ b/src/login/snapshot.rs @@ -1,6 +1,6 @@ use super::{ event::{Created, Event}, - Id, + Id, Name, }; // This also implements FromRequestParts (see `./extract.rs`). As a result, it @@ -10,7 +10,7 @@ use super::{ #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct Login { pub id: Id, - pub name: String, + pub name: Name, // The omission of the hashed password is deliberate, to minimize the // chance that it ends up tangled up in debug output or in some other chunk // of logic elsewhere. diff --git a/src/message/app.rs b/src/message/app.rs index 4e50513..af87553 100644 --- a/src/message/app.rs +++ b/src/message/app.rs @@ -2,7 +2,7 @@ use chrono::TimeDelta; use itertools::Itertools; use sqlx::sqlite::SqlitePool; -use super::{repo::Provider as _, Id, Message}; +use super::{repo::Provider as _, Body, Id, Message}; use crate::{ channel::{self, repo::Provider as _}, clock::DateTime, @@ -26,7 +26,7 @@ impl<'a> Messages<'a> { channel: &channel::Id, sender: &Login, sent_at: &DateTime, - body: &str, + body: &Body, ) -> Result<Message, SendError> { let mut tx = self.db.begin().await?; let channel = tx diff --git a/src/message/body.rs b/src/message/body.rs new file mode 100644 index 0000000..a415f85 --- /dev/null +++ b/src/message/body.rs @@ -0,0 +1,30 @@ +use std::fmt; + +use crate::nfc; + +#[derive( + Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, sqlx::Type, +)] +#[serde(transparent)] +#[sqlx(transparent)] +pub struct Body(nfc::String); + +impl fmt::Display for Body { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(body) = self; + body.fmt(f) + } +} + +impl From<String> for Body { + fn from(body: String) -> Self { + Self(body.into()) + } +} + +impl From<Body> for String { + fn from(body: Body) -> Self { + let Body(body) = body; + body.into() + } +} diff --git a/src/message/mod.rs b/src/message/mod.rs index a8f51ab..c2687bc 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -1,4 +1,5 @@ pub mod app; +mod body; pub mod event; mod history; mod id; @@ -6,4 +7,6 @@ pub mod repo; mod routes; mod snapshot; -pub use self::{event::Event, history::History, id::Id, routes::router, snapshot::Message}; +pub use self::{ + body::Body, event::Event, history::History, id::Id, routes::router, snapshot::Message, +}; diff --git a/src/message/repo.rs b/src/message/repo.rs index 85a69fc..4cfefec 100644 --- a/src/message/repo.rs +++ b/src/message/repo.rs @@ -1,6 +1,6 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; -use super::{snapshot::Message, History, Id}; +use super::{snapshot::Message, Body, History, Id}; use crate::{ channel, clock::DateTime, @@ -26,24 +26,24 @@ impl<'c> Messages<'c> { channel: &channel::History, sender: &Login, sent: &Instant, - body: &str, + body: &Body, ) -> Result<History, sqlx::Error> { let id = Id::generate(); let channel_id = channel.id(); let message = sqlx::query!( r#" - insert into message - (id, channel, sender, sent_at, sent_sequence, body) - values ($1, $2, $3, $4, $5, $6) - returning - id as "id: Id", + insert into message + (id, channel, sender, sent_at, sent_sequence, body) + values ($1, $2, $3, $4, $5, $6) + returning + id as "id: Id", channel as "channel: channel::Id", sender as "sender: login::Id", sent_at as "sent_at: DateTime", sent_sequence as "sent_sequence: Sequence", - body - "#, + body as "body: Body" + "#, id, channel_id, sender.id, @@ -76,7 +76,7 @@ impl<'c> Messages<'c> { message.channel as "channel: channel::Id", message.sender as "sender: login::Id", id as "id: Id", - message.body, + message.body as "body: Body", message.sent_at as "sent_at: DateTime", message.sent_sequence as "sent_sequence: Sequence", deleted.deleted_at as "deleted_at: DateTime", @@ -113,7 +113,7 @@ impl<'c> Messages<'c> { message.channel as "channel: channel::Id", message.sender as "sender: login::Id", id as "id: Id", - message.body, + message.body as "body: Body", message.sent_at as "sent_at: DateTime", message.sent_sequence as "sent_sequence: Sequence", deleted.deleted_at as "deleted_at: DateTime", @@ -150,7 +150,7 @@ impl<'c> Messages<'c> { message.channel as "channel: channel::Id", message.sender as "sender: login::Id", id as "id: Id", - message.body, + message.body as "body: Body", message.sent_at as "sent_at: DateTime", message.sent_sequence as "sent_sequence: Sequence", deleted.deleted_at as "deleted_at?: DateTime", @@ -256,7 +256,7 @@ impl<'c> Messages<'c> { message.sender as "sender: login::Id", message.sent_at as "sent_at: DateTime", message.sent_sequence as "sent_sequence: Sequence", - message.body, + message.body as "body: Body", deleted.deleted_at as "deleted_at?: DateTime", deleted.deleted_sequence as "deleted_sequence?: Sequence" from message @@ -293,7 +293,7 @@ impl<'c> Messages<'c> { message.sender as "sender: login::Id", message.sent_at as "sent_at: DateTime", message.sent_sequence as "sent_sequence: Sequence", - message.body, + message.body as "body: Body", deleted.deleted_at as "deleted_at: DateTime", deleted.deleted_sequence as "deleted_sequence: Sequence" from message diff --git a/src/message/snapshot.rs b/src/message/snapshot.rs index 7300918..53b7176 100644 --- a/src/message/snapshot.rs +++ b/src/message/snapshot.rs @@ -1,6 +1,6 @@ use super::{ event::{Event, Sent}, - Id, + Body, Id, }; use crate::{channel, clock::DateTime, event::Instant, login}; @@ -11,7 +11,7 @@ pub struct Message { pub channel: channel::Id, pub sender: login::Id, pub id: Id, - pub body: String, + pub body: Body, #[serde(skip_serializing_if = "Option::is_none")] pub deleted_at: Option<DateTime>, } diff --git a/src/nfc.rs b/src/nfc.rs new file mode 100644 index 0000000..70e936c --- /dev/null +++ b/src/nfc.rs @@ -0,0 +1,103 @@ +use std::{fmt, string::String as StdString}; + +use sqlx::{ + encode::{Encode, IsNull}, + Database, Decode, Type, +}; +use unicode_normalization::UnicodeNormalization as _; + +#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +#[serde(from = "StdString", into = "StdString")] +pub struct String(StdString); + +impl fmt::Display for String { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(value) = self; + value.fmt(f) + } +} + +impl From<StdString> for String { + fn from(value: StdString) -> Self { + let value = value.nfc().collect(); + + Self(value) + } +} + +impl From<String> for StdString { + fn from(value: String) -> Self { + let String(value) = value; + value + } +} + +impl std::ops::Deref for String { + type Target = StdString; + + fn deref(&self) -> &Self::Target { + let Self(value) = self; + value + } +} + +// Type is manually implemented so that we can implement Decode to do +// normalization on read. Implementation is otherwise based on +// `#[derive(sqlx::Type)]` with the `#[sqlx(transparent)]` attribute. +impl<DB> Type<DB> for String +where + DB: Database, + StdString: Type<DB>, +{ + fn type_info() -> <DB as Database>::TypeInfo { + <StdString as Type<DB>>::type_info() + } + + fn compatible(ty: &<DB as Database>::TypeInfo) -> bool { + <StdString as Type<DB>>::compatible(ty) + } +} + +impl<'r, DB> Decode<'r, DB> for String +where + DB: Database, + StdString: Decode<'r, DB>, +{ + fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> { + let value = StdString::decode(value)?; + let value = value.nfc().collect(); + Ok(Self(value)) + } +} + +impl<'q, DB> Encode<'q, DB> for String +where + DB: Database, + StdString: Encode<'q, DB>, +{ + fn encode_by_ref( + &self, + buf: &mut <DB as Database>::ArgumentBuffer<'q>, + ) -> Result<IsNull, sqlx::error::BoxDynError> { + let Self(value) = self; + value.encode_by_ref(buf) + } + + fn encode( + self, + buf: &mut <DB as Database>::ArgumentBuffer<'q>, + ) -> Result<IsNull, sqlx::error::BoxDynError> { + let Self(value) = self; + value.encode(buf) + } + + fn produces(&self) -> Option<<DB as Database>::TypeInfo> { + let Self(value) = self; + value.produces() + } + + fn size_hint(&self) -> usize { + let Self(value) = self; + value.size_hint() + } +} diff --git a/src/setup/app.rs b/src/setup/app.rs index d015813..9fbcf6d 100644 --- a/src/setup/app.rs +++ b/src/setup/app.rs @@ -4,7 +4,7 @@ use super::repo::Provider as _; use crate::{ clock::DateTime, event::{repo::Provider as _, Broadcaster, Event}, - login::{repo::Provider as _, Login, Password}, + login::{repo::Provider as _, Login, Name, Password}, token::{repo::Provider as _, Secret}, }; @@ -20,7 +20,7 @@ impl<'a> Setup<'a> { pub async fn initial( &self, - name: &str, + name: &Name, password: &Password, created_at: &DateTime, ) -> Result<(Login, Secret), Error> { diff --git a/src/setup/routes/post.rs b/src/setup/routes/post.rs index 34f4ed2..6a3fa11 100644 --- a/src/setup/routes/post.rs +++ b/src/setup/routes/post.rs @@ -8,7 +8,7 @@ use crate::{ app::App, clock::RequestedAt, error::Internal, - login::{Login, Password}, + login::{Login, Name, Password}, setup::app, token::extract::IdentityToken, }; @@ -30,7 +30,7 @@ pub async fn handler( #[derive(serde::Deserialize)] pub struct Request { - pub name: String, + pub name: Name, pub password: Password, } diff --git a/src/test/fixtures/channel.rs b/src/test/fixtures/channel.rs index a1dda61..024ac1b 100644 --- a/src/test/fixtures/channel.rs +++ b/src/test/fixtures/channel.rs @@ -8,7 +8,7 @@ use rand; use crate::{ app::App, - channel::{self, Channel}, + channel::{self, Channel, Name}, clock::RequestedAt, event::Event, }; @@ -21,13 +21,13 @@ pub async fn create(app: &App, created_at: &RequestedAt) -> Channel { .expect("should always succeed if the channel is actually new") } -pub fn propose() -> String { - rand::random::<Name>().to_string() +pub fn propose() -> Name { + rand::random::<NameTemplate>().to_string().into() } -struct Name(String); +struct NameTemplate(String); faker_impl_from_templates! { - Name; "{} {}", CityName, FullName; + NameTemplate; "{} {}", CityName, FullName; } pub fn events(event: Event) -> future::Ready<Option<channel::Event>> { diff --git a/src/test/fixtures/login.rs b/src/test/fixtures/login.rs index b6766fe..0a42320 100644 --- a/src/test/fixtures/login.rs +++ b/src/test/fixtures/login.rs @@ -4,7 +4,7 @@ use uuid::Uuid; use crate::{ app::App, clock::RequestedAt, - login::{self, Login, Password}, + login::{self, Login, Name, Password}, }; pub async fn create_with_password(app: &App, created_at: &RequestedAt) -> (Login, Password) { @@ -29,16 +29,16 @@ pub async fn create(app: &App, created_at: &RequestedAt) -> Login { pub fn fictitious() -> Login { Login { id: login::Id::generate(), - name: name(), + name: propose_name(), } } -pub fn propose() -> (String, Password) { - (name(), propose_password()) +pub fn propose() -> (Name, Password) { + (propose_name(), propose_password()) } -fn name() -> String { - rand::random::<internet::Username>().to_string() +fn propose_name() -> Name { + rand::random::<internet::Username>().to_string().into() } pub fn propose_password() -> Password { diff --git a/src/test/fixtures/message.rs b/src/test/fixtures/message.rs index eb00e7c..c450bce 100644 --- a/src/test/fixtures/message.rs +++ b/src/test/fixtures/message.rs @@ -8,7 +8,7 @@ use crate::{ clock::RequestedAt, event::Event, login::Login, - message::{self, Message}, + message::{self, Body, Message}, }; pub async fn send(app: &App, channel: &Channel, login: &Login, sent_at: &RequestedAt) -> Message { @@ -20,8 +20,8 @@ pub async fn send(app: &App, channel: &Channel, login: &Login, sent_at: &Request .expect("should succeed if the channel exists") } -pub fn propose() -> String { - rand::random::<Paragraphs>().to_string() +pub fn propose() -> Body { + rand::random::<Paragraphs>().to_string().into() } pub fn events(event: Event) -> future::Ready<Option<message::Event>> { diff --git a/src/token/app.rs b/src/token/app.rs index 0dc1a46..d4dd1a0 100644 --- a/src/token/app.rs +++ b/src/token/app.rs @@ -12,7 +12,7 @@ use super::{ use crate::{ clock::DateTime, db::NotFound as _, - login::{Login, Password}, + login::{Login, Name, Password}, }; pub struct Tokens<'a> { @@ -27,7 +27,7 @@ impl<'a> Tokens<'a> { pub async fn login( &self, - name: &str, + name: &Name, password: &Password, login_at: &DateTime, ) -> Result<(Login, Secret), LoginError> { diff --git a/src/token/repo/auth.rs b/src/token/repo/auth.rs index 88d0878..c621b65 100644 --- a/src/token/repo/auth.rs +++ b/src/token/repo/auth.rs @@ -3,7 +3,7 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use crate::{ clock::DateTime, event::{Instant, Sequence}, - login::{self, password::StoredHash, History, Login}, + login::{self, password::StoredHash, History, Login, Name}, }; pub trait Provider { @@ -19,12 +19,12 @@ impl<'c> Provider for Transaction<'c, Sqlite> { pub struct Auth<'t>(&'t mut SqliteConnection); impl<'t> Auth<'t> { - pub async fn for_name(&mut self, name: &str) -> Result<(History, StoredHash), sqlx::Error> { + pub async fn for_name(&mut self, name: &Name) -> Result<(History, StoredHash), sqlx::Error> { let found = sqlx::query!( r#" select id as "id: login::Id", - name, + name as "name: Name", password_hash as "password_hash: StoredHash", created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" diff --git a/src/token/repo/token.rs b/src/token/repo/token.rs index c592dcd..960bb72 100644 --- a/src/token/repo/token.rs +++ b/src/token/repo/token.rs @@ -3,7 +3,7 @@ use uuid::Uuid; use crate::{ clock::DateTime, - login::{self, History, Login}, + login::{self, History, Login, Name}, token::{Id, Secret}, }; @@ -128,7 +128,7 @@ impl<'c> Tokens<'c> { select token.id as "token_id: Id", login.id as "login_id: login::Id", - login.name as "login_name" + login.name as "login_name: Name" from login join token on login.id = token.login where token.secret = $1 |
