Detach authentication
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
# Stuff that helped:
|
# Stuff that helped
|
||||||
|
|
||||||
* Architecture:
|
* Architecture:
|
||||||
- [How to apply hexagonal architecture to Rust](https://www.barrage.net/blog/technology/how-to-apply-hexagonal-architecture-to-rust)
|
- [How to apply hexagonal architecture to Rust](https://www.barrage.net/blog/technology/how-to-apply-hexagonal-architecture-to-rust)
|
||||||
@ -11,9 +11,10 @@
|
|||||||
- [Building a simple text editor with iced, a cross-platform GUI library for Rust](https://www.youtube.com/watch?v=gcBJ7cPSALo)
|
- [Building a simple text editor with iced, a cross-platform GUI library for Rust](https://www.youtube.com/watch?v=gcBJ7cPSALo)
|
||||||
- [Unofficial Iced Guide](https://jl710.github.io/iced-guide/)
|
- [Unofficial Iced Guide](https://jl710.github.io/iced-guide/)
|
||||||
- [icebreaker](https://github.com/hecrj/icebreaker)
|
- [icebreaker](https://github.com/hecrj/icebreaker)
|
||||||
|
- [Halloy](https://github.com/squidowl/halloy)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
> _The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise._
|
> _The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise._
|
||||||
|
|
||||||
— Edsger W. Dijkstra
|
— _Edsger W. Dijkstra_
|
||||||
|
@ -22,7 +22,7 @@ CREATE TABLE PackageBases (
|
|||||||
description VARCHAR(510) NULL,
|
description VARCHAR(510) NULL,
|
||||||
|
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
-- User roles for working on packages: flagger, packager, submitter, maintainer, etc.
|
-- User roles for working on packages: flagger, packager, submitter, maintainer, etc.
|
||||||
@ -62,7 +62,7 @@ CREATE TABLE Packages (
|
|||||||
|
|
||||||
flagged_at TIMESTAMP NULL,
|
flagged_at TIMESTAMP NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
FOREIGN KEY (base) REFERENCES PackageBases (id) ON DELETE CASCADE
|
FOREIGN KEY (base) REFERENCES PackageBases (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
use crate::Result;
|
||||||
use crate::port::search::{Data, Entry, Mode, Order, SearchRepository};
|
use crate::port::search::{Data, Entry, Mode, Order, SearchRepository};
|
||||||
use crate::{Result, adapter::mysql::search};
|
|
||||||
|
|
||||||
// use chrono::Utc;
|
// use chrono::Utc;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use sqlx::{Executor, MySql, QueryBuilder, Row};
|
use sqlx::{Executor, MySql, QueryBuilder, Row};
|
||||||
|
|
||||||
pub struct UserAdapter;
|
pub struct SearchAdapter;
|
||||||
|
|
||||||
impl<E> SearchRepository<E> for UserAdapter
|
impl<E> SearchRepository<E> for SearchAdapter
|
||||||
where
|
where
|
||||||
E: Send,
|
E: Send,
|
||||||
for<'a> &'a E: Executor<'a, Database = MySql>,
|
for<'a> &'a E: Executor<'a, Database = MySql>,
|
||||||
@ -139,13 +139,13 @@ mod tests {
|
|||||||
let data = Data {
|
let data = Data {
|
||||||
mode: Mode::NameAndDescription,
|
mode: Mode::NameAndDescription,
|
||||||
order: Order::UpdatedAt,
|
order: Order::UpdatedAt,
|
||||||
search: Search::new("f")?,
|
search: Search::new("f").map_err(|e| e.1)?,
|
||||||
limit: 50,
|
limit: 50,
|
||||||
exact: true,
|
exact: true,
|
||||||
ascending: false,
|
ascending: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
UserAdapter::search(&pool, data).await?;
|
SearchAdapter::search(&pool, data).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,11 @@ pub use chrono::Utc;
|
|||||||
pub use adapter::mysql::base::BaseAdapter as MySqlBaseAdapter;
|
pub use adapter::mysql::base::BaseAdapter as MySqlBaseAdapter;
|
||||||
pub use adapter::mysql::package::PackageAdapter as MySqlPackageAdapter;
|
pub use adapter::mysql::package::PackageAdapter as MySqlPackageAdapter;
|
||||||
pub use adapter::mysql::user::UserAdapter as MySqlUserAdapter;
|
pub use adapter::mysql::user::UserAdapter as MySqlUserAdapter;
|
||||||
|
pub use adapter::mysql::search::SearchAdapter as MySqlSearchAdapter;
|
||||||
pub use atomic::Atomic;
|
pub use atomic::Atomic;
|
||||||
pub use connect::*;
|
pub use connect::*;
|
||||||
pub use port::base::{Base, BaseRepository};
|
pub use port::base::{Base, BaseRepository};
|
||||||
pub use port::package::{Package, PackageRepository};
|
pub use port::package::{Package, PackageRepository};
|
||||||
|
pub use port::search::{Search, SearchRepository};
|
||||||
pub use port::user::{User, UserRepository};
|
pub use port::user::{User, UserRepository};
|
||||||
pub use port::*;
|
pub use port::*;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ pub struct Data {
|
|||||||
pub order: Order,
|
pub order: Order,
|
||||||
pub search: Search,
|
pub search: Search,
|
||||||
|
|
||||||
pub limit: u8,
|
pub limit: u16,
|
||||||
pub exact: bool,
|
pub exact: bool,
|
||||||
pub ascending: bool,
|
pub ascending: bool,
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ impl TryFrom<String> for Name {
|
|||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
#[derive(Validate)]
|
#[derive(Validate)]
|
||||||
#[garde(transparent)]
|
#[garde(transparent)]
|
||||||
struct Username<'a>(#[garde(ascii, length(chars, min = 2, max = 31))] &'a str);
|
struct Username<'a>(#[garde(alphanumeric, length(chars, min = 2, max = 31))] &'a str);
|
||||||
|
|
||||||
match Username(value.as_str()).validate() {
|
match Username(value.as_str()).validate() {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
pub mod authentication;
|
pub mod authentication;
|
||||||
|
pub mod search;
|
||||||
|
|
||||||
pub use authentication::{
|
pub use authentication::{
|
||||||
Authenticated, AuthenticationAdapter, AuthenticationContract, AuthenticationRepository,
|
Authenticated, AuthenticationAdapter, AuthenticationContract, AuthenticationRepository,
|
||||||
AuthenticationService,
|
AuthenticationService,
|
||||||
};
|
};
|
||||||
|
pub use search::{Search, SearchAdapter, SearchContract, SearchRepository, SearchService};
|
||||||
// pub
|
|
||||||
|
9
src/service/src/search.rs
Normal file
9
src/service/src/search.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub mod adapter;
|
||||||
|
pub mod contract;
|
||||||
|
pub mod repository;
|
||||||
|
pub mod service;
|
||||||
|
|
||||||
|
pub use adapter::*;
|
||||||
|
pub use contract::*;
|
||||||
|
pub use repository::*;
|
||||||
|
pub use service::*;
|
43
src/service/src/search/adapter.rs
Normal file
43
src/service/src/search/adapter.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use data::search::*;
|
||||||
|
use data::{Connect, Result};
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct SearchAdapter<D, C, UR>
|
||||||
|
where
|
||||||
|
C: Send,
|
||||||
|
D: Connect<Connection = C> + Sync,
|
||||||
|
UR: SearchRepository<C> + Sync,
|
||||||
|
{
|
||||||
|
driver: D,
|
||||||
|
_search_repository: PhantomData<UR>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, C, UR> SearchAdapter<D, C, UR>
|
||||||
|
where
|
||||||
|
C: Send,
|
||||||
|
D: Connect<Connection = C> + Sync,
|
||||||
|
UR: SearchRepository<C> + Sync,
|
||||||
|
{
|
||||||
|
pub const fn new(driver: D) -> Self {
|
||||||
|
Self {
|
||||||
|
driver,
|
||||||
|
_search_repository: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, C, SR> super::SearchRepository for SearchAdapter<D, C, SR>
|
||||||
|
where
|
||||||
|
C: Send, //+ Sync,
|
||||||
|
D: Connect<Connection = C> + Sync,
|
||||||
|
SR: SearchRepository<C> + Sync,
|
||||||
|
{
|
||||||
|
async fn search(&self, data: Data) -> Result<Vec<Entry>> {
|
||||||
|
let c = self.driver.open_connection().await?;
|
||||||
|
let result = SR::search(&c, data).await?;
|
||||||
|
D::close_connection(c).await?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
60
src/service/src/search/contract.rs
Normal file
60
src/service/src/search/contract.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use data::{BoxDynError, search};
|
||||||
|
pub use data::{
|
||||||
|
Result, Validation,
|
||||||
|
search::{Mode, Order, Entry},
|
||||||
|
};
|
||||||
|
|
||||||
|
use derive_more::{Deref, Into};
|
||||||
|
use garde::Validate;
|
||||||
|
|
||||||
|
pub trait SearchContract: Send {
|
||||||
|
fn search(&self, data: Data) -> impl Future<Output = Result<Vec<Entry>>> + Send;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
pub mode: Mode,
|
||||||
|
pub order: Order,
|
||||||
|
pub search: Search,
|
||||||
|
|
||||||
|
pub limit: u16,
|
||||||
|
pub exact: bool,
|
||||||
|
pub ascending: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Data> for search::Data {
|
||||||
|
fn from(value: Data) -> Self {
|
||||||
|
Self {
|
||||||
|
mode: value.mode,
|
||||||
|
order: value.order,
|
||||||
|
search: value.search.into(),
|
||||||
|
limit: value.limit,
|
||||||
|
exact: value.exact,
|
||||||
|
ascending: value.ascending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ReturnError<T = String> = (T, BoxDynError);
|
||||||
|
|
||||||
|
#[derive(Clone, Deref, Into)]
|
||||||
|
pub struct Search(search::Search);
|
||||||
|
impl AsRef<str> for Search {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<String> for Search {
|
||||||
|
type Error = ReturnError;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
#[derive(Validate)]
|
||||||
|
#[garde(transparent)]
|
||||||
|
struct Check<'a>(#[garde(ascii, length(chars, min = 1, max = 255))] &'a str);
|
||||||
|
|
||||||
|
match Check(value.as_str()).validate() {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(e) => return Err((value, e.into())),
|
||||||
|
}
|
||||||
|
Ok(Self(search::Search::new(value)?))
|
||||||
|
}
|
||||||
|
}
|
6
src/service/src/search/repository.rs
Normal file
6
src/service/src/search/repository.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use data::Result;
|
||||||
|
use data::search::{Data, Entry};
|
||||||
|
|
||||||
|
pub trait SearchRepository {
|
||||||
|
fn search(&self, data: Data) -> impl Future<Output = Result<Vec<Entry>>> + Send;
|
||||||
|
}
|
27
src/service/src/search/service.rs
Normal file
27
src/service/src/search/service.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use super::{Data, Result, SearchContract, SearchRepository};
|
||||||
|
use data::search;
|
||||||
|
|
||||||
|
pub struct SearchService<R>
|
||||||
|
where
|
||||||
|
R: SearchRepository,
|
||||||
|
{
|
||||||
|
pub(crate) repository: R,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> SearchService<R>
|
||||||
|
where
|
||||||
|
R: SearchRepository,
|
||||||
|
{
|
||||||
|
pub const fn new(repository: R) -> Self {
|
||||||
|
Self { repository }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> SearchContract for SearchService<R>
|
||||||
|
where
|
||||||
|
R: SearchRepository + Send + Sync,
|
||||||
|
{
|
||||||
|
async fn search(&self, data: Data) -> Result<Vec<search::Entry>> {
|
||||||
|
self.repository.search(data.into()).await
|
||||||
|
}
|
||||||
|
}
|
83
src/src/authentication.rs
Normal file
83
src/src/authentication.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
mod login;
|
||||||
|
mod register;
|
||||||
|
|
||||||
|
use login::Login;
|
||||||
|
use register::Register;
|
||||||
|
|
||||||
|
use service::{Authenticated, AuthenticationContract};
|
||||||
|
|
||||||
|
use iced::{Element, Task, futures::lock::Mutex};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Authentication<S> {
|
||||||
|
login: Login<S>,
|
||||||
|
register: Register<S>,
|
||||||
|
screen: Screen,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Screen {
|
||||||
|
Login,
|
||||||
|
Register,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Message {
|
||||||
|
Login(login::Message),
|
||||||
|
Register(register::Message),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
Task(Task<Message>),
|
||||||
|
Authenticated(Authenticated),
|
||||||
|
}
|
||||||
|
impl From<Task<Message>> for Event {
|
||||||
|
fn from(value: Task<Message>) -> Self {
|
||||||
|
Self::Task(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: AuthenticationContract + 'static> Authentication<S> {
|
||||||
|
pub fn new(service: Arc<Mutex<S>>) -> Self {
|
||||||
|
Self {
|
||||||
|
login: Login::new(service.clone()),
|
||||||
|
register: Register::new(service),
|
||||||
|
screen: Screen::Login,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, message: Message) -> Option<Event> {
|
||||||
|
Some(match message {
|
||||||
|
Message::Login(message) => match self.login.update(message)? {
|
||||||
|
login::Event::SwitchToRegister => {
|
||||||
|
self.screen = Screen::Register;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
login::Event::Task(task) => task.map(Message::Login).into(),
|
||||||
|
login::Event::Authenticated(x) => Event::Authenticated(x),
|
||||||
|
},
|
||||||
|
Message::Register(message) => match self.register.update(message)? {
|
||||||
|
register::Event::SwitchToLogin => {
|
||||||
|
self.screen = Screen::Login;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
register::Event::Task(task) => task.map(Message::Register).into(),
|
||||||
|
register::Event::Authenticated(x) => Event::Authenticated(x),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view(&self) -> Element<Message> {
|
||||||
|
match self.screen {
|
||||||
|
Screen::Login => self.login.view().map(Message::Login),
|
||||||
|
Screen::Register => self.register.view().map(Message::Register),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(&self) -> String {
|
||||||
|
match self.screen {
|
||||||
|
Screen::Login => self.login.title(),
|
||||||
|
Screen::Register => self.register.title(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ pub struct Login<S> {
|
|||||||
enum State {
|
enum State {
|
||||||
None,
|
None,
|
||||||
Requesting,
|
Requesting,
|
||||||
|
Success,
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +105,10 @@ impl<S: AuthenticationContract + 'static> Login<S> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Message::RequestResult(r) => match &*r {
|
Message::RequestResult(r) => match &*r {
|
||||||
Ok(a) => return Some(Event::Authenticated(a.clone())),
|
Ok(a) => {
|
||||||
|
self.state = State::Success;
|
||||||
|
return Some(Event::Authenticated(a.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.state = State::None;
|
self.state = State::None;
|
||||||
@ -170,6 +174,7 @@ impl<S: AuthenticationContract + 'static> Login<S> {
|
|||||||
|
|
||||||
match &self.state {
|
match &self.state {
|
||||||
State::None => error.map_or_else(|| "Login".into(), Into::into),
|
State::None => error.map_or_else(|| "Login".into(), Into::into),
|
||||||
|
State::Success => "Success".into(),
|
||||||
State::Requesting => "Requesting...".into(),
|
State::Requesting => "Requesting...".into(),
|
||||||
State::Error(e) => e.into(),
|
State::Error(e) => e.into(),
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use crate::input::Input;
|
use crate::input::{self, Input, Value};
|
||||||
use crate::widget::centerbox;
|
use crate::widget::centerbox;
|
||||||
use service::authentication::{self, Email, Name, Password, RegisterData};
|
use service::authentication::{self, Email, Name, Password, RegisterData};
|
||||||
use service::{
|
use service::{
|
||||||
@ -15,7 +15,7 @@ pub struct Register<S> {
|
|||||||
name: Input<Name>,
|
name: Input<Name>,
|
||||||
email: Input<Email>,
|
email: Input<Email>,
|
||||||
password: Input<Password>,
|
password: Input<Password>,
|
||||||
repeat: Input<Password>,
|
repeat: Input<String>,
|
||||||
show_password: bool,
|
show_password: bool,
|
||||||
|
|
||||||
state: State,
|
state: State,
|
||||||
@ -23,6 +23,7 @@ pub struct Register<S> {
|
|||||||
}
|
}
|
||||||
enum State {
|
enum State {
|
||||||
None,
|
None,
|
||||||
|
Success,
|
||||||
Requesting,
|
Requesting,
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
@ -72,7 +73,10 @@ impl<S: AuthenticationContract + 'static> Register<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_passwords(&mut self) {
|
fn check_passwords(&mut self) {
|
||||||
if self.password.as_ref() != self.repeat.as_ref() {
|
if self.password.as_ref() == self.repeat.as_ref() {
|
||||||
|
self.repeat
|
||||||
|
.set_value(Value::Valid(self.repeat.as_ref().to_string()));
|
||||||
|
} else {
|
||||||
self.repeat.set_error(&"passwords are different");
|
self.repeat.set_error(&"passwords are different");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +90,7 @@ impl<S: AuthenticationContract + 'static> Register<S> {
|
|||||||
self.check_passwords();
|
self.check_passwords();
|
||||||
}
|
}
|
||||||
Message::RepeatChanged(s) => {
|
Message::RepeatChanged(s) => {
|
||||||
self.repeat.update(s);
|
self.repeat.set_value(Value::Valid(s));
|
||||||
self.check_passwords();
|
self.check_passwords();
|
||||||
}
|
}
|
||||||
Message::ShowPasswordToggled(b) => self.show_password = b,
|
Message::ShowPasswordToggled(b) => self.show_password = b,
|
||||||
@ -97,10 +101,10 @@ impl<S: AuthenticationContract + 'static> Register<S> {
|
|||||||
Message::EmailSubmitted => return Some(self.password.focus().into()),
|
Message::EmailSubmitted => return Some(self.password.focus().into()),
|
||||||
Message::PasswordSubmitted if self.password.critical() => (),
|
Message::PasswordSubmitted if self.password.critical() => (),
|
||||||
Message::PasswordSubmitted => return Some(self.repeat.focus().into()),
|
Message::PasswordSubmitted => return Some(self.repeat.focus().into()),
|
||||||
Message::RepeatSubmitted if self.repeat.critical() => (),
|
Message::RepeatSubmitted if self.repeat.error().is_some() => (),
|
||||||
|
|
||||||
Message::RegisterPressed | Message::RepeatSubmitted => {
|
Message::RegisterPressed | Message::RepeatSubmitted => {
|
||||||
if self.repeat.critical() {
|
if self.repeat.error().is_some() {
|
||||||
return Some(self.repeat.focus().into());
|
return Some(self.repeat.focus().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +144,10 @@ impl<S: AuthenticationContract + 'static> Register<S> {
|
|||||||
|
|
||||||
Message::LoginPressed => return Some(Event::SwitchToLogin),
|
Message::LoginPressed => return Some(Event::SwitchToLogin),
|
||||||
Message::RequestResult(r) => match &*r {
|
Message::RequestResult(r) => match &*r {
|
||||||
Ok(a) => return Some(Event::Authenticated(a.clone())),
|
Ok(a) => {
|
||||||
|
self.state = State::Success;
|
||||||
|
return Some(Event::Authenticated(a.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.state = State::None;
|
self.state = State::None;
|
||||||
@ -220,6 +227,7 @@ impl<S: AuthenticationContract + 'static> Register<S> {
|
|||||||
|
|
||||||
match &self.state {
|
match &self.state {
|
||||||
State::None => error.map_or_else(|| "Register".into(), Into::into),
|
State::None => error.map_or_else(|| "Register".into(), Into::into),
|
||||||
|
State::Success => "Success".into(),
|
||||||
State::Requesting => "Requesting...".into(),
|
State::Requesting => "Requesting...".into(),
|
||||||
State::Error(e) => e.into(),
|
State::Error(e) => e.into(),
|
||||||
}
|
}
|
@ -1,15 +1,12 @@
|
|||||||
// mod main_window;
|
// mod main_window;
|
||||||
// mod authentication;
|
// mod authentication;
|
||||||
|
mod authentication;
|
||||||
mod input;
|
mod input;
|
||||||
mod login;
|
|
||||||
mod register;
|
|
||||||
mod widget;
|
mod widget;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::login::Login;
|
use crate::authentication::Authentication;
|
||||||
use crate::register::Register;
|
|
||||||
// use crate::authentication::Authentication;
|
|
||||||
// use crate::main_window::MainWindow;
|
// use crate::main_window::MainWindow;
|
||||||
|
|
||||||
use data::{MySqlPool, MySqlUserAdapter, SqlxPool};
|
use data::{MySqlPool, MySqlUserAdapter, SqlxPool};
|
||||||
@ -40,18 +37,9 @@ fn main() -> iced::Result {
|
|||||||
struct Repository {
|
struct Repository {
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
main_id: window::Id,
|
main_id: window::Id,
|
||||||
login:
|
authentication: Authentication<
|
||||||
Login<AuthenticationService<AuthenticationAdapter<MySqlPool, SqlxPool, MySqlUserAdapter>>>,
|
|
||||||
register: Register<
|
|
||||||
AuthenticationService<AuthenticationAdapter<MySqlPool, SqlxPool, MySqlUserAdapter>>,
|
AuthenticationService<AuthenticationAdapter<MySqlPool, SqlxPool, MySqlUserAdapter>>,
|
||||||
>,
|
>,
|
||||||
screen: Screen,
|
|
||||||
// authentication: Authentication,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Screen {
|
|
||||||
Login,
|
|
||||||
Register,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -61,8 +49,7 @@ enum Message {
|
|||||||
WindowOpened(window::Id),
|
WindowOpened(window::Id),
|
||||||
WindowClosed(window::Id),
|
WindowClosed(window::Id),
|
||||||
|
|
||||||
Login(login::Message),
|
Authentecation(authentication::Message),
|
||||||
Register(register::Message),
|
|
||||||
// MainWindow(main_window::Message),
|
// MainWindow(main_window::Message),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +74,7 @@ impl Repository {
|
|||||||
Self {
|
Self {
|
||||||
scale_factor: 1.4,
|
scale_factor: 1.4,
|
||||||
main_id,
|
main_id,
|
||||||
login: Login::new(auth_service.clone()),
|
authentication: Authentication::new(auth_service),
|
||||||
register: Register::new(auth_service),
|
|
||||||
screen: Screen::Login,
|
|
||||||
},
|
},
|
||||||
Task::batch([
|
Task::batch([
|
||||||
open_task.map(Message::WindowOpened),
|
open_task.map(Message::WindowOpened),
|
||||||
@ -112,24 +97,14 @@ impl Repository {
|
|||||||
return iced::exit();
|
return iced::exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Login(message) => {
|
Message::Authentecation(message) => {
|
||||||
if let Some(action) = self.login.update(message) {
|
if let Some(action) = self.authentication.update(message) {
|
||||||
match action {
|
match action {
|
||||||
login::Event::SwitchToRegister => self.screen = Screen::Register,
|
authentication::Event::Task(task) => {
|
||||||
login::Event::Task(task) => return task.map(Message::Login),
|
return task.map(Message::Authentecation);
|
||||||
login::Event::Authenticated(authenticated) => {
|
|
||||||
log!("authenticated via login {:#?}", authenticated);
|
|
||||||
}
|
}
|
||||||
}
|
authentication::Event::Authenticated(authenticated) => {
|
||||||
}
|
log!("authenticated via login {:#?}", authenticated);
|
||||||
}
|
|
||||||
Message::Register(message) => {
|
|
||||||
if let Some(action) = self.register.update(message) {
|
|
||||||
match action {
|
|
||||||
register::Event::SwitchToLogin => self.screen = Screen::Login,
|
|
||||||
register::Event::Task(task) => return task.map(Message::Register),
|
|
||||||
register::Event::Authenticated(authenticated) => {
|
|
||||||
log!("authenticated via register: {:#?}", authenticated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,10 +120,7 @@ impl Repository {
|
|||||||
fn view(&self, id: window::Id) -> Element<Message> {
|
fn view(&self, id: window::Id) -> Element<Message> {
|
||||||
if self.main_id == id {
|
if self.main_id == id {
|
||||||
// self.main_window.view().map(Message::MainWindow)
|
// self.main_window.view().map(Message::MainWindow)
|
||||||
match self.screen {
|
self.authentication.view().map(Message::Authentecation)
|
||||||
Screen::Login => self.login.view().map(Message::Login),
|
|
||||||
Screen::Register => self.register.view().map(Message::Register),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
center(row!["This window is unknown.", "It may be closed."]).into()
|
center(row!["This window is unknown.", "It may be closed."]).into()
|
||||||
}
|
}
|
||||||
@ -156,10 +128,7 @@ impl Repository {
|
|||||||
|
|
||||||
fn title(&self, _: window::Id) -> String {
|
fn title(&self, _: window::Id) -> String {
|
||||||
// "Repository".into()
|
// "Repository".into()
|
||||||
match self.screen {
|
self.authentication.title()
|
||||||
Screen::Login => self.login.title(),
|
|
||||||
Screen::Register => self.register.title(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
|
Reference in New Issue
Block a user