Refactor: delete unused crates (#2543)

* refactor: delete user model

* refactor: delete user model crate

* refactor: rm flowy-server-sync crate

* refactor: rm flowy-database and flowy-folder

* refactor: rm folder-model

* refactor: rm database model

* refactor: rm flowy-sync

* refactor: rm document-model

* refactor: rm flowy-document

* refactor: rm flowy-client-sync

* refactor: rm ws-model

* refactor: rm flowy-revisoin

* refactor: rm revision-model

* refactor: rm flowy-folder

* refactor: rm flowy-client-ws

* refactor: move crates

* chore: move configuration file

* ci: fix tauri build'

* ci: fix flutter build

* ci: rust test script

* ci: tauri pnpm version conflict

* ci: tauri build
This commit is contained in:
Nathan.fooo
2023-05-17 09:49:39 +08:00
committed by GitHub
parent 2202326278
commit bc66f43f47
514 changed files with 2274 additions and 55304 deletions

View File

@ -6,10 +6,9 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
flowy-derive = { path = "../flowy-derive" }
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-sqlite = { path = "../flowy-sqlite", optional = true }
flowy-error = { path = "../flowy-error", features = ["adaptor_database", "adaptor_dispatch", "adaptor_user"] }
user-model = { path = "../../../shared-lib/user-model" }
flowy-error = { path = "../flowy-error", features = ["adaptor_database", "adaptor_dispatch"] }
lib-infra = { path = "../../../shared-lib/lib-infra" }
flowy-notification = { path = "../flowy-notification" }
lib-dispatch = { path = "../lib-dispatch" }
@ -29,10 +28,18 @@ parking_lot = "0.12.1"
strum = "0.21"
strum_macros = "0.21"
tokio = { version = "1.26", features = ["rt"] }
validator = "0.16.0"
unicode-segmentation = "1.10"
fancy-regex = "0.11.0"
[dev-dependencies]
flowy-test = { path = "../flowy-test" }
nanoid = "0.4.0"
fake = "2.0.0"
rand = "0.8.4"
quickcheck = "1.0.3"
rand_core = "0.6.2"
quickcheck_macros = "1.0"
[features]
default = ["rev-sqlite"]
@ -41,4 +48,4 @@ dart = ["flowy-codegen/dart", "flowy-notification/dart"]
ts = ["flowy-codegen/ts", "flowy-notification/ts"]
[build-dependencies]
flowy-codegen = { path = "../flowy-codegen"}
flowy-codegen = { path = "../../../shared-lib/flowy-codegen"}

View File

@ -1,7 +1,11 @@
use crate::errors::ErrorCode;
use flowy_derive::ProtoBuf;
use std::convert::TryInto;
use user_model::{SignInParams, SignUpParams, UserEmail, UserName, UserPassword};
use serde::{Deserialize, Serialize};
use flowy_derive::ProtoBuf;
use crate::entities::parser::*;
use crate::errors::ErrorCode;
#[derive(ProtoBuf, Default)]
pub struct SignInPayloadPB {
@ -56,3 +60,91 @@ impl TryInto<SignUpParams> for SignUpPayloadPB {
})
}
}
#[derive(Default, Serialize, Deserialize, Debug)]
pub struct SignInParams {
pub email: String,
pub password: String,
pub name: String,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct SignInResponse {
pub user_id: i64,
pub name: String,
pub email: String,
pub token: String,
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct SignUpParams {
pub email: String,
pub name: String,
pub password: String,
}
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct SignUpResponse {
pub user_id: i64,
pub name: String,
pub email: String,
pub token: String,
}
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct UserProfile {
pub id: i64,
pub email: String,
pub name: String,
pub token: String,
pub icon_url: String,
pub openai_key: String,
}
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct UpdateUserProfileParams {
pub id: i64,
pub name: Option<String>,
pub email: Option<String>,
pub password: Option<String>,
pub icon_url: Option<String>,
pub openai_key: Option<String>,
}
impl UpdateUserProfileParams {
pub fn new(id: i64) -> Self {
Self {
id,
name: None,
email: None,
password: None,
icon_url: None,
openai_key: None,
}
}
pub fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_owned());
self
}
pub fn email(mut self, email: &str) -> Self {
self.email = Some(email.to_owned());
self
}
pub fn password(mut self, password: &str) -> Self {
self.password = Some(password.to_owned());
self
}
pub fn icon_url(mut self, icon_url: &str) -> Self {
self.icon_url = Some(icon_url.to_owned());
self
}
pub fn openai_key(mut self, openai_key: &str) -> Self {
self.openai_key = Some(openai_key.to_owned());
self
}
}

View File

@ -3,5 +3,6 @@ pub use user_profile::*;
pub use user_setting::*;
pub mod auth;
pub mod parser;
mod user_profile;
mod user_setting;

View File

@ -0,0 +1,16 @@
// https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
mod user_email;
mod user_icon;
mod user_id;
mod user_name;
mod user_openai_key;
mod user_password;
mod user_workspace;
pub use user_email::*;
pub use user_icon::*;
pub use user_id::*;
pub use user_name::*;
pub use user_openai_key::*;
pub use user_password::*;
pub use user_workspace::*;

View File

@ -0,0 +1,73 @@
use flowy_error::ErrorCode;
use validator::validate_email;
#[derive(Debug)]
pub struct UserEmail(pub String);
impl UserEmail {
pub fn parse(s: String) -> Result<UserEmail, ErrorCode> {
if s.trim().is_empty() {
return Err(ErrorCode::EmailIsEmpty);
}
if validate_email(&s) {
Ok(Self(s))
} else {
Err(ErrorCode::EmailFormatInvalid)
}
}
}
impl AsRef<str> for UserEmail {
fn as_ref(&self) -> &str {
&self.0
}
}
#[cfg(test)]
mod tests {
use fake::{faker::internet::en::SafeEmail, Fake};
use rand::prelude::StdRng;
use rand_core::SeedableRng;
use super::*;
#[test]
fn empty_string_is_rejected() {
let email = "".to_string();
assert!(UserEmail::parse(email).is_err());
}
#[test]
fn email_missing_at_symbol_is_rejected() {
let email = "helloworld.com".to_string();
assert!(UserEmail::parse(email).is_err());
}
#[test]
fn email_missing_subject_is_rejected() {
let email = "@domain.com".to_string();
assert!(UserEmail::parse(email).is_err());
}
#[derive(Debug, Clone)]
struct ValidEmailFixture(pub String);
impl quickcheck::Arbitrary for ValidEmailFixture {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut rand_slice: [u8; 32] = [0; 32];
#[allow(clippy::needless_range_loop)]
for i in 0..32 {
rand_slice[i] = u8::arbitrary(g);
}
let mut seed = StdRng::from_seed(rand_slice);
let email = SafeEmail().fake_with_rng(&mut seed);
Self(email)
}
}
#[quickcheck_macros::quickcheck]
fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
UserEmail::parse(valid_email.0).is_ok()
}
}

View File

@ -0,0 +1,16 @@
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserIcon(pub String);
impl UserIcon {
pub fn parse(s: String) -> Result<UserIcon, ErrorCode> {
Ok(Self(s))
}
}
impl AsRef<str> for UserIcon {
fn as_ref(&self) -> &str {
&self.0
}
}

View File

@ -0,0 +1,20 @@
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserId(pub String);
impl UserId {
pub fn parse(s: String) -> Result<UserId, ErrorCode> {
let is_empty_or_whitespace = s.trim().is_empty();
if is_empty_or_whitespace {
return Err(ErrorCode::UserIdInvalid);
}
Ok(Self(s))
}
}
impl AsRef<str> for UserId {
fn as_ref(&self) -> &str {
&self.0
}
}

View File

@ -0,0 +1,84 @@
use unicode_segmentation::UnicodeSegmentation;
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserName(pub String);
impl UserName {
pub fn parse(s: String) -> Result<UserName, ErrorCode> {
let is_empty_or_whitespace = s.trim().is_empty();
if is_empty_or_whitespace {
return Err(ErrorCode::UserNameIsEmpty);
}
// A grapheme is defined by the Unicode standard as a "user-perceived"
// character: `å` is a single grapheme, but it is composed of two characters
// (`a` and `̊`).
//
// `graphemes` returns an iterator over the graphemes in the input `s`.
// `true` specifies that we want to use the extended grapheme definition set,
// the recommended one.
let is_too_long = s.graphemes(true).count() > 256;
if is_too_long {
return Err(ErrorCode::UserNameTooLong);
}
let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
if contains_forbidden_characters {
return Err(ErrorCode::UserNameContainForbiddenCharacters);
}
Ok(Self(s))
}
}
impl AsRef<str> for UserName {
fn as_ref(&self) -> &str {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::UserName;
#[test]
fn a_256_grapheme_long_name_is_valid() {
let name = "".repeat(256);
assert!(UserName::parse(name).is_ok());
}
#[test]
fn a_name_longer_than_256_graphemes_is_rejected() {
let name = "a".repeat(257);
assert!(UserName::parse(name).is_err());
}
#[test]
fn whitespace_only_names_are_rejected() {
let name = " ".to_string();
assert!(UserName::parse(name).is_err());
}
#[test]
fn empty_string_is_rejected() {
let name = "".to_string();
assert!(UserName::parse(name).is_err());
}
#[test]
fn names_containing_an_invalid_character_are_rejected() {
for name in &['/', '(', ')', '"', '<', '>', '\\', '{', '}'] {
let name = name.to_string();
assert!(UserName::parse(name).is_err());
}
}
#[test]
fn a_valid_name_is_parsed_successfully() {
let name = "nathan".to_string();
assert!(UserName::parse(name).is_ok());
}
}

View File

@ -0,0 +1,16 @@
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserOpenaiKey(pub String);
impl UserOpenaiKey {
pub fn parse(s: String) -> Result<UserOpenaiKey, ErrorCode> {
Ok(Self(s))
}
}
impl AsRef<str> for UserOpenaiKey {
fn as_ref(&self) -> &str {
&self.0
}
}

View File

@ -0,0 +1,65 @@
use lazy_static::lazy_static;
use unicode_segmentation::UnicodeSegmentation;
use fancy_regex::Regex;
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserPassword(pub String);
impl UserPassword {
pub fn parse(s: String) -> Result<UserPassword, ErrorCode> {
if s.trim().is_empty() {
return Err(ErrorCode::PasswordIsEmpty);
}
if s.graphemes(true).count() > 100 {
return Err(ErrorCode::PasswordTooLong);
}
let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
if contains_forbidden_characters {
return Err(ErrorCode::PasswordContainsForbidCharacters);
}
if !validate_password(&s) {
return Err(ErrorCode::PasswordFormatInvalid);
}
Ok(Self(s))
}
}
impl AsRef<str> for UserPassword {
fn as_ref(&self) -> &str {
&self.0
}
}
lazy_static! {
// Test it in https://regex101.com/
// https://stackoverflow.com/questions/2370015/regular-expression-for-password-validation/2370045
// Hell1!
// [invalid, greater or equal to 6]
// Hel1!
//
// Hello1!
// [invalid, must include number]
// Hello!
//
// Hello12!
// [invalid must include upper case]
// hello12!
static ref PASSWORD: Regex = Regex::new("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\\W]).{6,20})").unwrap();
}
pub fn validate_password(password: &str) -> bool {
match PASSWORD.is_match(password) {
Ok(is_match) => is_match,
Err(e) => {
tracing::error!("validate_password fail: {:?}", e);
false
},
}
}

View File

@ -0,0 +1,20 @@
use flowy_error::ErrorCode;
#[derive(Debug)]
pub struct UserWorkspace(pub String);
impl UserWorkspace {
pub fn parse(s: String) -> Result<UserWorkspace, ErrorCode> {
let is_empty_or_whitespace = s.trim().is_empty();
if is_empty_or_whitespace {
return Err(ErrorCode::WorkspaceIdInvalid);
}
Ok(Self(s))
}
}
impl AsRef<str> for UserWorkspace {
fn as_ref(&self) -> &str {
&self.0
}
}

View File

@ -1,9 +1,10 @@
use crate::errors::ErrorCode;
use flowy_derive::ProtoBuf;
use std::convert::TryInto;
use user_model::{
UpdateUserProfileParams, UserEmail, UserIcon, UserName, UserOpenaiKey, UserPassword, UserProfile,
};
use flowy_derive::ProtoBuf;
use crate::entities::parser::{UserEmail, UserIcon, UserName, UserOpenaiKey, UserPassword};
use crate::entities::{UpdateUserProfileParams, UserProfile};
use crate::errors::ErrorCode;
#[derive(Default, ProtoBuf)]
pub struct UserTokenPB {

View File

@ -1,10 +1,12 @@
use crate::entities::*;
use crate::services::UserSession;
use std::{convert::TryInto, sync::Arc};
use flowy_error::FlowyError;
use flowy_sqlite::kv::KV;
use lib_dispatch::prelude::*;
use std::{convert::TryInto, sync::Arc};
use user_model::{SignInParams, SignUpParams, UpdateUserProfileParams};
use crate::entities::*;
use crate::entities::{SignInParams, SignUpParams, UpdateUserProfileParams};
use crate::services::UserSession;
// tracing instrument 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html
#[tracing::instrument(level = "debug", name = "sign_in", skip(data, session), fields(email = %data.email), err)]

View File

@ -1,15 +1,18 @@
use crate::entities::UserProfilePB;
use crate::event_handler::*;
use crate::{errors::FlowyError, services::UserSession};
use std::sync::Arc;
use strum_macros::Display;
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
use flowy_error::FlowyResult;
use lib_dispatch::prelude::*;
use lib_infra::future::{Fut, FutureResult};
use std::sync::Arc;
use strum_macros::Display;
use user_model::{
use crate::entities::UserProfilePB;
use crate::entities::{
SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile,
};
use crate::event_handler::*;
use crate::{errors::FlowyError, services::UserSession};
pub fn init(user_session: Arc<UserSession>) -> AFPlugin {
AFPlugin::new()

View File

@ -8,7 +8,8 @@ use parking_lot::RwLock;
use flowy_error::FlowyError;
use flowy_sqlite::ConnectionPool;
use flowy_sqlite::{schema::user_table, DBConnection, Database};
use user_model::{SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfile};
use crate::entities::{SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfile};
pub struct UserDB {
db_dir: String,

View File

@ -11,10 +11,10 @@ use flowy_sqlite::{
schema::{user_table, user_table::dsl},
DBConnection, ExpressionMethods, UserDatabaseConnection,
};
use user_model::{
use crate::entities::{
SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile,
};
use crate::entities::{UserProfilePB, UserSettingPB};
use crate::event_map::UserStatusCallback;
use crate::{
@ -24,9 +24,6 @@ use crate::{
services::database::{UserDB, UserTable, UserTableChangeset},
};
// lazy_static! {
// static ref ID_GEN: Mutex<UserIDGenerator> = Mutex::new(UserIDGenerator::new(1));
// }
pub struct UserSessionConfig {
root_dir: String,