mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
test server api: register user and sign in
This commit is contained in:
parent
15f1267956
commit
f05f0c43a3
15 changed files with 170 additions and 41 deletions
|
@ -58,4 +58,11 @@ path = "src/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "backend"
|
name = "backend"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
once_cell = "1.7.2"
|
||||||
|
actix-rt = "2"
|
||||||
|
tokio = { version = "1", features = ["macros"] }
|
||||||
|
linkify = "0.5.0"
|
||||||
|
flowy-user = { path = "../rust-lib/flowy-user" }
|
|
@ -34,6 +34,8 @@ impl Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> { self.server.await }
|
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> { self.server.await }
|
||||||
|
|
||||||
|
pub fn port(&self) -> u16 { self.port }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
|
pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
|
||||||
|
@ -64,8 +66,8 @@ fn user_scope() -> Scope {
|
||||||
web::scope("/api")
|
web::scope("/api")
|
||||||
// authentication
|
// authentication
|
||||||
.service(web::resource("/auth")
|
.service(web::resource("/auth")
|
||||||
.route(web::post().to(user_router::login_handler))
|
.route(web::post().to(user_router::sign_in_handler))
|
||||||
.route(web::delete().to(user_router::logout_handler))
|
.route(web::delete().to(user_router::sign_out_handler))
|
||||||
.route(web::get().to(user_router::user_profile))
|
.route(web::get().to(user_router::user_profile))
|
||||||
)
|
)
|
||||||
// password
|
// password
|
||||||
|
@ -74,7 +76,7 @@ fn user_scope() -> Scope {
|
||||||
)
|
)
|
||||||
// register
|
// register
|
||||||
.service(web::resource("/register")
|
.service(web::resource("/register")
|
||||||
.route(web::post().to(user_router::register_handler))
|
.route(web::post().to(user_router::register_user_handler))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
// type mapped https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub(crate) id: uuid::Uuid,
|
pub(crate) id: uuid::Uuid,
|
||||||
pub(crate) email: String,
|
pub(crate) email: String,
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) create_time: i64,
|
pub(crate) create_time: chrono::DateTime<Utc>,
|
||||||
pub(crate) password: String,
|
pub(crate) password: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use flowy_net::errors::ServerError;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub async fn login_handler(
|
pub async fn sign_in_handler(
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
pool: Data<PgPool>,
|
pool: Data<PgPool>,
|
||||||
|
@ -24,7 +24,7 @@ pub async fn login_handler(
|
||||||
Ok(resp.into())
|
Ok(resp.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn logout_handler(id: Identity) -> Result<HttpResponse, ServerError> {
|
pub async fn sign_out_handler(id: Identity) -> Result<HttpResponse, ServerError> {
|
||||||
id.forget();
|
id.forget();
|
||||||
Ok(HttpResponse::Ok().finish())
|
Ok(HttpResponse::Ok().finish())
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ pub async fn user_profile(
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register_handler(
|
pub async fn register_user_handler(
|
||||||
_request: HttpRequest,
|
_request: HttpRequest,
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
pool: Data<PgPool>,
|
pool: Data<PgPool>,
|
||||||
|
|
|
@ -116,7 +116,7 @@ async fn insert_user(
|
||||||
params.email,
|
params.email,
|
||||||
params.name,
|
params.name,
|
||||||
Utc::now(),
|
Utc::now(),
|
||||||
"123".to_string()
|
password,
|
||||||
)
|
)
|
||||||
.execute(transaction)
|
.execute(transaction)
|
||||||
.await
|
.await
|
||||||
|
|
39
backend/tests/api/auth.rs
Normal file
39
backend/tests/api/auth.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use crate::helper::spawn_app;
|
||||||
|
use flowy_user::entities::{SignInParams, SignInResponse, SignUpParams};
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn user_register() {
|
||||||
|
let app = spawn_app().await;
|
||||||
|
let params = SignUpParams {
|
||||||
|
email: "annie@appflowy.io".to_string(),
|
||||||
|
name: "annie".to_string(),
|
||||||
|
password: "123".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = app.register_user(params).await;
|
||||||
|
log::info!("{:?}", response);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn user_sign_in() {
|
||||||
|
let app = spawn_app().await;
|
||||||
|
let email = "annie@appflowy.io";
|
||||||
|
let password = "123";
|
||||||
|
|
||||||
|
let _ = app
|
||||||
|
.register_user(SignUpParams {
|
||||||
|
email: email.to_string(),
|
||||||
|
name: "annie".to_string(),
|
||||||
|
password: password.to_string(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let response = app
|
||||||
|
.sign_in(SignInParams {
|
||||||
|
email: email.to_string(),
|
||||||
|
password: password.to_string(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
log::info!("{:?}", response);
|
||||||
|
}
|
77
backend/tests/api/helper.rs
Normal file
77
backend/tests/api/helper.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use backend::{
|
||||||
|
application::{get_connection_pool, Application},
|
||||||
|
config::{get_configuration, DatabaseSettings},
|
||||||
|
};
|
||||||
|
use flowy_net::request::HttpRequestBuilder;
|
||||||
|
use flowy_user::prelude::*;
|
||||||
|
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub struct TestApp {
|
||||||
|
pub address: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub pg_pool: PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestApp {
|
||||||
|
pub async fn register_user(&self, params: SignUpParams) -> SignUpResponse {
|
||||||
|
let url = format!("{}/api/register", self.address);
|
||||||
|
let resp = user_sign_up(params, &url).await.unwrap();
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sign_in(&self, params: SignInParams) -> SignInResponse {
|
||||||
|
let url = format!("{}/api/auth", self.address);
|
||||||
|
let resp = user_sign_in(params, &url).await.unwrap();
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn spawn_app() -> TestApp {
|
||||||
|
let configuration = {
|
||||||
|
let mut c = get_configuration().expect("Failed to read configuration.");
|
||||||
|
c.database.database_name = Uuid::new_v4().to_string();
|
||||||
|
// Use a random OS port
|
||||||
|
c.application.port = 0;
|
||||||
|
c
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = configure_database(&configuration.database).await;
|
||||||
|
let application = Application::build(configuration.clone())
|
||||||
|
.await
|
||||||
|
.expect("Failed to build application.");
|
||||||
|
let application_port = application.port();
|
||||||
|
|
||||||
|
let _ = tokio::spawn(application.run_until_stopped());
|
||||||
|
|
||||||
|
TestApp {
|
||||||
|
address: format!("http://localhost:{}", application_port),
|
||||||
|
port: application_port,
|
||||||
|
pg_pool: get_connection_pool(&configuration.database)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to the database"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn configure_database(config: &DatabaseSettings) -> PgPool {
|
||||||
|
// Create database
|
||||||
|
let mut connection = PgConnection::connect_with(&config.without_db())
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to Postgres");
|
||||||
|
connection
|
||||||
|
.execute(&*format!(r#"CREATE DATABASE "{}";"#, config.database_name))
|
||||||
|
.await
|
||||||
|
.expect("Failed to create database.");
|
||||||
|
|
||||||
|
// Migrate database
|
||||||
|
let connection_pool = PgPool::connect_with(config.with_db())
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to Postgres.");
|
||||||
|
|
||||||
|
sqlx::migrate!("./migrations")
|
||||||
|
.run(&connection_pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to migrate the database");
|
||||||
|
|
||||||
|
connection_pool
|
||||||
|
}
|
2
backend/tests/api/main.rs
Normal file
2
backend/tests/api/main.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mod auth;
|
||||||
|
mod helper;
|
|
@ -43,7 +43,7 @@ impl RustStreamSender {
|
||||||
pub fn post(_observable_subject: ObservableSubject) -> Result<(), String> {
|
pub fn post(_observable_subject: ObservableSubject) -> Result<(), String> {
|
||||||
#[cfg(feature = "dart")]
|
#[cfg(feature = "dart")]
|
||||||
match R2F_STREAM_SENDER.read() {
|
match R2F_STREAM_SENDER.read() {
|
||||||
Ok(stream) => stream.inner_post(observable_subject),
|
Ok(stream) => stream.inner_post(_observable_subject),
|
||||||
Err(e) => Err(format!("Get rust to flutter stream lock fail. {:?}", e)),
|
Err(e) => Err(format!("Get rust to flutter stream lock fail. {:?}", e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,6 @@ pub use user_detail::*;
|
||||||
pub use user_update::*;
|
pub use user_update::*;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod sign_in;
|
mod sign_in;
|
||||||
mod sign_up;
|
pub mod sign_up;
|
||||||
mod user_detail;
|
mod user_detail;
|
||||||
mod user_update;
|
mod user_update;
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub struct SignInParams {
|
||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, ProtoBuf)]
|
#[derive(Debug, Default, ProtoBuf)]
|
||||||
pub struct SignInResponse {
|
pub struct SignInResponse {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
mod event;
|
||||||
|
mod handlers;
|
||||||
|
mod sql_tables;
|
||||||
|
|
||||||
pub mod entities;
|
pub mod entities;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod event;
|
|
||||||
mod handlers;
|
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod protobuf;
|
pub mod protobuf;
|
||||||
mod services;
|
pub mod services;
|
||||||
pub mod sql_tables;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate flowy_database;
|
extern crate flowy_database;
|
||||||
|
@ -13,7 +14,6 @@ extern crate flowy_database;
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
entities::*,
|
entities::*,
|
||||||
handlers::*,
|
|
||||||
services::{user::*, workspace::*},
|
services::{user::*, workspace::*},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,18 +26,13 @@ pub(crate) fn construct_server() -> Arc<dyn UserServer + Send + Sync> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserServerImpl {}
|
pub struct UserServerImpl {}
|
||||||
impl UserServerImpl {}
|
impl UserServerImpl {
|
||||||
|
pub fn new() -> Self { Self {} }
|
||||||
|
}
|
||||||
|
|
||||||
impl UserServer for UserServerImpl {
|
impl UserServer for UserServerImpl {
|
||||||
fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
|
fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
|
||||||
ResultFuture::new(async move {
|
ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await })
|
||||||
let response = HttpRequestBuilder::post(SIGN_UP_URL.as_ref())
|
|
||||||
.protobuf(params)?
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.response()?;
|
|
||||||
Ok(response)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self, _params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
fn sign_in(&self, _params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
||||||
|
@ -60,6 +55,24 @@ impl UserServer for UserServerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn user_sign_up(params: SignUpParams, url: &str) -> Result<SignUpResponse, UserError> {
|
||||||
|
let response = HttpRequestBuilder::post(&url.to_owned())
|
||||||
|
.protobuf(params)?
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.response()?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn user_sign_in(params: SignInParams, url: &str) -> Result<SignInResponse, UserError> {
|
||||||
|
let response = HttpRequestBuilder::post(&url.to_owned())
|
||||||
|
.protobuf(params)?
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.response()?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UserServerMock {}
|
pub struct UserServerMock {}
|
||||||
|
|
||||||
impl UserServer for UserServerMock {
|
impl UserServer for UserServerMock {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
mod user_test;
|
|
|
@ -1,14 +0,0 @@
|
||||||
use flowy_user::prelude::*;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn user_register_test() {
|
|
||||||
let server = UserServerImpl {};
|
|
||||||
|
|
||||||
let params = SignUpParams {
|
|
||||||
email: "annie@appflowy.io".to_string(),
|
|
||||||
name: "annie".to_string(),
|
|
||||||
password: "1233333".to_string(),
|
|
||||||
};
|
|
||||||
let result = server.sign_up(params).await.unwrap();
|
|
||||||
println!("{:?}", result);
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue