Kould
kould
commited on
Commit
·
d94c6df
1
Parent(s):
c64dcb9
feat: Implement authentication (#10)
Browse filesCo-authored-by: kould <[email protected]>
- Cargo.toml +4 -0
- migration/src/m20220101_000001_create_table.rs +2 -0
- src/api/dialog_info.rs +13 -13
- src/api/doc_info.rs +15 -18
- src/api/kb_info.rs +10 -10
- src/api/mod.rs +2 -1
- src/api/{tag.rs → tag_info.rs} +13 -11
- src/api/user_info.rs +52 -0
- src/entity/tag_info.rs +2 -2
- src/entity/user_info.rs +3 -2
- src/errors.rs +82 -0
- src/main.rs +55 -4
- src/service/dialog_info.rs +1 -1
- src/service/doc_info.rs +1 -2
- src/service/kb_info.rs +1 -1
- src/service/mod.rs +2 -1
- src/service/tag_info.rs +1 -1
- src/service/user_info.rs +105 -0
Cargo.toml
CHANGED
@@ -10,6 +10,10 @@ actix-web = "4.3.1"
|
|
10 |
actix-rt = "2.8.0"
|
11 |
actix-files = "0.6.2"
|
12 |
actix-multipart = "0.4"
|
|
|
|
|
|
|
|
|
13 |
postgres = "0.19.7"
|
14 |
sea-orm = {version = "0.12.9", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"]}
|
15 |
serde = { version = "1", features = ["derive"] }
|
|
|
10 |
actix-rt = "2.8.0"
|
11 |
actix-files = "0.6.2"
|
12 |
actix-multipart = "0.4"
|
13 |
+
actix-session = { version = "0.5" }
|
14 |
+
actix-identity = { version = "0.4" }
|
15 |
+
actix-web-httpauth = { version = "0.6" }
|
16 |
+
thiserror = "1.0"
|
17 |
postgres = "0.19.7"
|
18 |
sea-orm = {version = "0.12.9", features = ["sqlx-postgres", "runtime-tokio-native-tls", "macros"]}
|
19 |
serde = { version = "1", features = ["derive"] }
|
migration/src/m20220101_000001_create_table.rs
CHANGED
@@ -24,6 +24,7 @@ impl MigrationTrait for Migration {
|
|
24 |
.col(ColumnDef::new(UserInfo::ColorSchema).string().default("dark"))
|
25 |
.col(ColumnDef::new(UserInfo::ListStyle).string().default("list"))
|
26 |
.col(ColumnDef::new(UserInfo::Language).string().default("chinese"))
|
|
|
27 |
.col(ColumnDef::new(UserInfo::CreatedAt).date().not_null())
|
28 |
.col(ColumnDef::new(UserInfo::UpdatedAt).date().not_null())
|
29 |
.col(ColumnDef::new(UserInfo::IsDeleted).boolean().default(false))
|
@@ -215,6 +216,7 @@ enum UserInfo {
|
|
215 |
ColorSchema,
|
216 |
ListStyle,
|
217 |
Language,
|
|
|
218 |
CreatedAt,
|
219 |
UpdatedAt,
|
220 |
IsDeleted,
|
|
|
24 |
.col(ColumnDef::new(UserInfo::ColorSchema).string().default("dark"))
|
25 |
.col(ColumnDef::new(UserInfo::ListStyle).string().default("list"))
|
26 |
.col(ColumnDef::new(UserInfo::Language).string().default("chinese"))
|
27 |
+
.col(ColumnDef::new(UserInfo::Password).string().not_null())
|
28 |
.col(ColumnDef::new(UserInfo::CreatedAt).date().not_null())
|
29 |
.col(ColumnDef::new(UserInfo::UpdatedAt).date().not_null())
|
30 |
.col(ColumnDef::new(UserInfo::IsDeleted).boolean().default(false))
|
|
|
216 |
ColorSchema,
|
217 |
ListStyle,
|
218 |
Language,
|
219 |
+
Password,
|
220 |
CreatedAt,
|
221 |
UpdatedAt,
|
222 |
IsDeleted,
|
src/api/dialog_info.rs
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
3 |
-
use actix_web::http::Error;
|
4 |
use crate::api::JsonResponse;
|
5 |
use crate::AppState;
|
6 |
use crate::entity::dialog_info;
|
|
|
7 |
use crate::service::dialog_info::Query;
|
8 |
use crate::service::dialog_info::Mutation;
|
9 |
|
10 |
#[get("/v1.0/dialogs")]
|
11 |
-
async fn list(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
12 |
-
let dialogs = Query::find_dialog_infos_by_uid(&data.conn, model.uid).await
|
13 |
|
14 |
let mut result = HashMap::new();
|
15 |
result.insert("dialogs", dialogs);
|
@@ -22,12 +22,12 @@ async fn list(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -
|
|
22 |
|
23 |
Ok(HttpResponse::Ok()
|
24 |
.content_type("application/json")
|
25 |
-
.body(serde_json::to_string(&json_response)
|
26 |
}
|
27 |
|
28 |
#[get("/v1.0/dialog")]
|
29 |
-
async fn detail(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
30 |
-
let dialogs = Query::find_dialog_info_by_id(&data.conn, model.dialog_id).await
|
31 |
|
32 |
let mut result = HashMap::new();
|
33 |
result.insert("dialogs", dialogs);
|
@@ -40,12 +40,12 @@ async fn detail(model: web::Json<dialog_info::Model>, data: web::Data<AppState>)
|
|
40 |
|
41 |
Ok(HttpResponse::Ok()
|
42 |
.content_type("application/json")
|
43 |
-
.body(serde_json::to_string(&json_response)
|
44 |
}
|
45 |
|
46 |
#[post("/v1.0/delete_dialog")]
|
47 |
-
async fn delete(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
48 |
-
let _ = Mutation::delete_dialog_info(&data.conn, model.dialog_id).await
|
49 |
|
50 |
let json_response = JsonResponse {
|
51 |
code: 200,
|
@@ -55,12 +55,12 @@ async fn delete(model: web::Json<dialog_info::Model>, data: web::Data<AppState>)
|
|
55 |
|
56 |
Ok(HttpResponse::Ok()
|
57 |
.content_type("application/json")
|
58 |
-
.body(serde_json::to_string(&json_response)
|
59 |
}
|
60 |
|
61 |
#[post("/v1.0/create_kb")]
|
62 |
-
async fn create(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
63 |
-
let model = Mutation::create_dialog_info(&data.conn, model.into_inner()).await
|
64 |
|
65 |
let mut result = HashMap::new();
|
66 |
result.insert("dialog_id", model.dialog_id.unwrap());
|
@@ -73,5 +73,5 @@ async fn create(model: web::Json<dialog_info::Model>, data: web::Data<AppState>)
|
|
73 |
|
74 |
Ok(HttpResponse::Ok()
|
75 |
.content_type("application/json")
|
76 |
-
.body(serde_json::to_string(&json_response)
|
77 |
}
|
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
|
|
3 |
use crate::api::JsonResponse;
|
4 |
use crate::AppState;
|
5 |
use crate::entity::dialog_info;
|
6 |
+
use crate::errors::AppError;
|
7 |
use crate::service::dialog_info::Query;
|
8 |
use crate::service::dialog_info::Mutation;
|
9 |
|
10 |
#[get("/v1.0/dialogs")]
|
11 |
+
async fn list(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
12 |
+
let dialogs = Query::find_dialog_infos_by_uid(&data.conn, model.uid).await?;
|
13 |
|
14 |
let mut result = HashMap::new();
|
15 |
result.insert("dialogs", dialogs);
|
|
|
22 |
|
23 |
Ok(HttpResponse::Ok()
|
24 |
.content_type("application/json")
|
25 |
+
.body(serde_json::to_string(&json_response)?))
|
26 |
}
|
27 |
|
28 |
#[get("/v1.0/dialog")]
|
29 |
+
async fn detail(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
30 |
+
let dialogs = Query::find_dialog_info_by_id(&data.conn, model.dialog_id).await?;
|
31 |
|
32 |
let mut result = HashMap::new();
|
33 |
result.insert("dialogs", dialogs);
|
|
|
40 |
|
41 |
Ok(HttpResponse::Ok()
|
42 |
.content_type("application/json")
|
43 |
+
.body(serde_json::to_string(&json_response)?))
|
44 |
}
|
45 |
|
46 |
#[post("/v1.0/delete_dialog")]
|
47 |
+
async fn delete(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
48 |
+
let _ = Mutation::delete_dialog_info(&data.conn, model.dialog_id).await?;
|
49 |
|
50 |
let json_response = JsonResponse {
|
51 |
code: 200,
|
|
|
55 |
|
56 |
Ok(HttpResponse::Ok()
|
57 |
.content_type("application/json")
|
58 |
+
.body(serde_json::to_string(&json_response)?))
|
59 |
}
|
60 |
|
61 |
#[post("/v1.0/create_kb")]
|
62 |
+
async fn create(model: web::Json<dialog_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
63 |
+
let model = Mutation::create_dialog_info(&data.conn, model.into_inner()).await?;
|
64 |
|
65 |
let mut result = HashMap::new();
|
66 |
result.insert("dialog_id", model.dialog_id.unwrap());
|
|
|
73 |
|
74 |
Ok(HttpResponse::Ok()
|
75 |
.content_type("application/json")
|
76 |
+
.body(serde_json::to_string(&json_response)?))
|
77 |
}
|
src/api/doc_info.rs
CHANGED
@@ -1,14 +1,14 @@
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_multipart::Multipart;
|
3 |
use actix_web::{get, HttpResponse, post, web};
|
4 |
-
use actix_web::http::Error;
|
5 |
use chrono::Local;
|
6 |
-
use futures_util::
|
7 |
use serde::Deserialize;
|
8 |
use std::io::Write;
|
9 |
use crate::api::JsonResponse;
|
10 |
use crate::AppState;
|
11 |
use crate::entity::doc_info::Model;
|
|
|
12 |
use crate::service::doc_info::{Mutation, Query};
|
13 |
|
14 |
#[derive(Debug, Deserialize)]
|
@@ -35,10 +35,9 @@ pub struct MvParams {
|
|
35 |
}
|
36 |
|
37 |
#[get("/v1.0/docs")]
|
38 |
-
async fn list(params: web::Json<Params>, data: web::Data<AppState>) -> Result<HttpResponse,
|
39 |
let docs = Query::find_doc_infos_by_params(&data.conn, params.into_inner())
|
40 |
-
.await
|
41 |
-
.unwrap();
|
42 |
|
43 |
let mut result = HashMap::new();
|
44 |
result.insert("docs", docs);
|
@@ -51,11 +50,11 @@ async fn list(params: web::Json<Params>, data: web::Data<AppState>) -> Result<Ht
|
|
51 |
|
52 |
Ok(HttpResponse::Ok()
|
53 |
.content_type("application/json")
|
54 |
-
.body(serde_json::to_string(&json_response)
|
55 |
}
|
56 |
|
57 |
#[post("/v1.0/upload")]
|
58 |
-
async fn upload(mut payload: Multipart, filename: web::Data<String>, did: web::Data<i64>, uid: web::Data<i64>, data: web::Data<AppState>) -> Result<HttpResponse,
|
59 |
let mut size = 0;
|
60 |
|
61 |
while let Some(item) = payload.next().await {
|
@@ -65,16 +64,14 @@ async fn upload(mut payload: Multipart, filename: web::Data<String>, did: web::D
|
|
65 |
|
66 |
let mut file = web::block(|| std::fs::File::create(filepath))
|
67 |
.await
|
68 |
-
.unwrap()
|
69 |
-
.unwrap();
|
70 |
|
71 |
while let Some(chunk) = field.next().await {
|
72 |
let data = chunk.unwrap();
|
73 |
size += data.len() as u64;
|
74 |
file = web::block(move || file.write_all(&data).map(|_| file))
|
75 |
.await
|
76 |
-
.unwrap()
|
77 |
-
.unwrap();
|
78 |
}
|
79 |
}
|
80 |
|
@@ -89,15 +86,15 @@ async fn upload(mut payload: Multipart, filename: web::Data<String>, did: web::D
|
|
89 |
r#type: "".to_string(),
|
90 |
created_at: Local::now().date_naive(),
|
91 |
updated_at: Local::now().date_naive(),
|
92 |
-
}).await
|
93 |
|
94 |
Ok(HttpResponse::Ok().body("File uploaded successfully"))
|
95 |
}
|
96 |
|
97 |
#[post("/v1.0/delete_docs")]
|
98 |
-
async fn delete(doc_ids: web::Json<Vec<i64>>, data: web::Data<AppState>) -> Result<HttpResponse,
|
99 |
for doc_id in doc_ids.iter() {
|
100 |
-
let _ = Mutation::delete_doc_info(&data.conn, *doc_id).await
|
101 |
}
|
102 |
|
103 |
let json_response = JsonResponse {
|
@@ -108,12 +105,12 @@ async fn delete(doc_ids: web::Json<Vec<i64>>, data: web::Data<AppState>) -> Resu
|
|
108 |
|
109 |
Ok(HttpResponse::Ok()
|
110 |
.content_type("application/json")
|
111 |
-
.body(serde_json::to_string(&json_response)
|
112 |
}
|
113 |
|
114 |
#[post("/v1.0/mv_docs")]
|
115 |
-
async fn mv(params: web::Json<MvParams>, data: web::Data<AppState>) -> Result<HttpResponse,
|
116 |
-
Mutation::mv_doc_info(&data.conn, params.dest_did, ¶ms.dids).await
|
117 |
|
118 |
let json_response = JsonResponse {
|
119 |
code: 200,
|
@@ -123,5 +120,5 @@ async fn mv(params: web::Json<MvParams>, data: web::Data<AppState>) -> Result<Ht
|
|
123 |
|
124 |
Ok(HttpResponse::Ok()
|
125 |
.content_type("application/json")
|
126 |
-
.body(serde_json::to_string(&json_response)
|
127 |
}
|
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_multipart::Multipart;
|
3 |
use actix_web::{get, HttpResponse, post, web};
|
|
|
4 |
use chrono::Local;
|
5 |
+
use futures_util::StreamExt;
|
6 |
use serde::Deserialize;
|
7 |
use std::io::Write;
|
8 |
use crate::api::JsonResponse;
|
9 |
use crate::AppState;
|
10 |
use crate::entity::doc_info::Model;
|
11 |
+
use crate::errors::AppError;
|
12 |
use crate::service::doc_info::{Mutation, Query};
|
13 |
|
14 |
#[derive(Debug, Deserialize)]
|
|
|
35 |
}
|
36 |
|
37 |
#[get("/v1.0/docs")]
|
38 |
+
async fn list(params: web::Json<Params>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
39 |
let docs = Query::find_doc_infos_by_params(&data.conn, params.into_inner())
|
40 |
+
.await?;
|
|
|
41 |
|
42 |
let mut result = HashMap::new();
|
43 |
result.insert("docs", docs);
|
|
|
50 |
|
51 |
Ok(HttpResponse::Ok()
|
52 |
.content_type("application/json")
|
53 |
+
.body(serde_json::to_string(&json_response)?))
|
54 |
}
|
55 |
|
56 |
#[post("/v1.0/upload")]
|
57 |
+
async fn upload(mut payload: Multipart, filename: web::Data<String>, did: web::Data<i64>, uid: web::Data<i64>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
58 |
let mut size = 0;
|
59 |
|
60 |
while let Some(item) = payload.next().await {
|
|
|
64 |
|
65 |
let mut file = web::block(|| std::fs::File::create(filepath))
|
66 |
.await
|
67 |
+
.unwrap()?;
|
|
|
68 |
|
69 |
while let Some(chunk) = field.next().await {
|
70 |
let data = chunk.unwrap();
|
71 |
size += data.len() as u64;
|
72 |
file = web::block(move || file.write_all(&data).map(|_| file))
|
73 |
.await
|
74 |
+
.unwrap()?;
|
|
|
75 |
}
|
76 |
}
|
77 |
|
|
|
86 |
r#type: "".to_string(),
|
87 |
created_at: Local::now().date_naive(),
|
88 |
updated_at: Local::now().date_naive(),
|
89 |
+
}).await?;
|
90 |
|
91 |
Ok(HttpResponse::Ok().body("File uploaded successfully"))
|
92 |
}
|
93 |
|
94 |
#[post("/v1.0/delete_docs")]
|
95 |
+
async fn delete(doc_ids: web::Json<Vec<i64>>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
96 |
for doc_id in doc_ids.iter() {
|
97 |
+
let _ = Mutation::delete_doc_info(&data.conn, *doc_id).await?;
|
98 |
}
|
99 |
|
100 |
let json_response = JsonResponse {
|
|
|
105 |
|
106 |
Ok(HttpResponse::Ok()
|
107 |
.content_type("application/json")
|
108 |
+
.body(serde_json::to_string(&json_response)?))
|
109 |
}
|
110 |
|
111 |
#[post("/v1.0/mv_docs")]
|
112 |
+
async fn mv(params: web::Json<MvParams>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
113 |
+
Mutation::mv_doc_info(&data.conn, params.dest_did, ¶ms.dids).await?;
|
114 |
|
115 |
let json_response = JsonResponse {
|
116 |
code: 200,
|
|
|
120 |
|
121 |
Ok(HttpResponse::Ok()
|
122 |
.content_type("application/json")
|
123 |
+
.body(serde_json::to_string(&json_response)?))
|
124 |
}
|
src/api/kb_info.rs
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
3 |
-
use actix_web::http::Error;
|
4 |
use crate::api::JsonResponse;
|
5 |
use crate::AppState;
|
6 |
use crate::entity::kb_info;
|
|
|
7 |
use crate::service::kb_info::Mutation;
|
8 |
use crate::service::kb_info::Query;
|
9 |
|
10 |
#[post("/v1.0/create_kb")]
|
11 |
-
async fn create(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
12 |
-
let model = Mutation::create_kb_info(&data.conn, model.into_inner()).await
|
13 |
|
14 |
let mut result = HashMap::new();
|
15 |
result.insert("kb_id", model.kb_id.unwrap());
|
@@ -22,12 +22,12 @@ async fn create(model: web::Json<kb_info::Model>, data: web::Data<AppState>) ->
|
|
22 |
|
23 |
Ok(HttpResponse::Ok()
|
24 |
.content_type("application/json")
|
25 |
-
.body(serde_json::to_string(&json_response)
|
26 |
}
|
27 |
|
28 |
#[get("/v1.0/kbs")]
|
29 |
-
async fn list(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
30 |
-
let kbs = Query::find_kb_infos_by_uid(&data.conn, model.uid).await
|
31 |
|
32 |
let mut result = HashMap::new();
|
33 |
result.insert("kbs", kbs);
|
@@ -40,12 +40,12 @@ async fn list(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Re
|
|
40 |
|
41 |
Ok(HttpResponse::Ok()
|
42 |
.content_type("application/json")
|
43 |
-
.body(serde_json::to_string(&json_response)
|
44 |
}
|
45 |
|
46 |
#[post("/v1.0/delete_kb")]
|
47 |
-
async fn delete(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
48 |
-
let _ = Mutation::delete_kb_info(&data.conn, model.kb_id).await
|
49 |
|
50 |
let json_response = JsonResponse {
|
51 |
code: 200,
|
@@ -55,5 +55,5 @@ async fn delete(model: web::Json<kb_info::Model>, data: web::Data<AppState>) ->
|
|
55 |
|
56 |
Ok(HttpResponse::Ok()
|
57 |
.content_type("application/json")
|
58 |
-
.body(serde_json::to_string(&json_response)
|
59 |
}
|
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
|
|
3 |
use crate::api::JsonResponse;
|
4 |
use crate::AppState;
|
5 |
use crate::entity::kb_info;
|
6 |
+
use crate::errors::AppError;
|
7 |
use crate::service::kb_info::Mutation;
|
8 |
use crate::service::kb_info::Query;
|
9 |
|
10 |
#[post("/v1.0/create_kb")]
|
11 |
+
async fn create(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
12 |
+
let model = Mutation::create_kb_info(&data.conn, model.into_inner()).await?;
|
13 |
|
14 |
let mut result = HashMap::new();
|
15 |
result.insert("kb_id", model.kb_id.unwrap());
|
|
|
22 |
|
23 |
Ok(HttpResponse::Ok()
|
24 |
.content_type("application/json")
|
25 |
+
.body(serde_json::to_string(&json_response)?))
|
26 |
}
|
27 |
|
28 |
#[get("/v1.0/kbs")]
|
29 |
+
async fn list(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
30 |
+
let kbs = Query::find_kb_infos_by_uid(&data.conn, model.uid).await?;
|
31 |
|
32 |
let mut result = HashMap::new();
|
33 |
result.insert("kbs", kbs);
|
|
|
40 |
|
41 |
Ok(HttpResponse::Ok()
|
42 |
.content_type("application/json")
|
43 |
+
.body(serde_json::to_string(&json_response)?))
|
44 |
}
|
45 |
|
46 |
#[post("/v1.0/delete_kb")]
|
47 |
+
async fn delete(model: web::Json<kb_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
48 |
+
let _ = Mutation::delete_kb_info(&data.conn, model.kb_id).await?;
|
49 |
|
50 |
let json_response = JsonResponse {
|
51 |
code: 200,
|
|
|
55 |
|
56 |
Ok(HttpResponse::Ok()
|
57 |
.content_type("application/json")
|
58 |
+
.body(serde_json::to_string(&json_response)?))
|
59 |
}
|
src/api/mod.rs
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
use serde::{Deserialize, Serialize};
|
2 |
|
3 |
-
pub(crate) mod
|
4 |
pub(crate) mod kb_info;
|
5 |
pub(crate) mod dialog_info;
|
6 |
pub(crate) mod doc_info;
|
|
|
7 |
|
8 |
#[derive(Debug, Deserialize, Serialize)]
|
9 |
struct JsonResponse<T> {
|
|
|
1 |
use serde::{Deserialize, Serialize};
|
2 |
|
3 |
+
pub(crate) mod tag_info;
|
4 |
pub(crate) mod kb_info;
|
5 |
pub(crate) mod dialog_info;
|
6 |
pub(crate) mod doc_info;
|
7 |
+
pub(crate) mod user_info;
|
8 |
|
9 |
#[derive(Debug, Deserialize, Serialize)]
|
10 |
struct JsonResponse<T> {
|
src/api/{tag.rs → tag_info.rs}
RENAMED
@@ -1,14 +1,16 @@
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
3 |
-
use
|
|
|
4 |
use crate::api::JsonResponse;
|
5 |
use crate::AppState;
|
6 |
use crate::entity::tag_info;
|
|
|
7 |
use crate::service::tag_info::{Mutation, Query};
|
8 |
|
9 |
#[post("/v1.0/create_tag")]
|
10 |
-
async fn create(model: web::Json<tag_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
11 |
-
let model = Mutation::create_tag(&data.conn, model.into_inner()).await
|
12 |
|
13 |
let mut result = HashMap::new();
|
14 |
result.insert("tid", model.tid.unwrap());
|
@@ -21,12 +23,12 @@ async fn create(model: web::Json<tag_info::Model>, data: web::Data<AppState>) ->
|
|
21 |
|
22 |
Ok(HttpResponse::Ok()
|
23 |
.content_type("application/json")
|
24 |
-
.body(serde_json::to_string(&json_response)
|
25 |
}
|
26 |
|
27 |
#[post("/v1.0/delete_tag")]
|
28 |
-
async fn delete(model: web::Json<tag_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse,
|
29 |
-
let _ = Mutation::delete_tag(&data.conn, model.tid).await
|
30 |
|
31 |
let json_response = JsonResponse {
|
32 |
code: 200,
|
@@ -36,12 +38,12 @@ async fn delete(model: web::Json<tag_info::Model>, data: web::Data<AppState>) ->
|
|
36 |
|
37 |
Ok(HttpResponse::Ok()
|
38 |
.content_type("application/json")
|
39 |
-
.body(serde_json::to_string(&json_response)
|
40 |
}
|
41 |
|
42 |
-
#[get("/v1.0/tags")]
|
43 |
-
async fn list(data: web::Data<AppState>) -> Result<HttpResponse,
|
44 |
-
let tags = Query::find_tag_infos(&data.conn).await
|
45 |
|
46 |
let mut result = HashMap::new();
|
47 |
result.insert("tags", tags);
|
@@ -54,5 +56,5 @@ async fn list(data: web::Data<AppState>) -> Result<HttpResponse, Error> {
|
|
54 |
|
55 |
Ok(HttpResponse::Ok()
|
56 |
.content_type("application/json")
|
57 |
-
.body(serde_json::to_string(&json_response)
|
58 |
}
|
|
|
1 |
use std::collections::HashMap;
|
2 |
use actix_web::{get, HttpResponse, post, web};
|
3 |
+
use actix_web_httpauth::middleware::HttpAuthentication;
|
4 |
+
use crate::validator;
|
5 |
use crate::api::JsonResponse;
|
6 |
use crate::AppState;
|
7 |
use crate::entity::tag_info;
|
8 |
+
use crate::errors::AppError;
|
9 |
use crate::service::tag_info::{Mutation, Query};
|
10 |
|
11 |
#[post("/v1.0/create_tag")]
|
12 |
+
async fn create(model: web::Json<tag_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
13 |
+
let model = Mutation::create_tag(&data.conn, model.into_inner()).await?;
|
14 |
|
15 |
let mut result = HashMap::new();
|
16 |
result.insert("tid", model.tid.unwrap());
|
|
|
23 |
|
24 |
Ok(HttpResponse::Ok()
|
25 |
.content_type("application/json")
|
26 |
+
.body(serde_json::to_string(&json_response)?))
|
27 |
}
|
28 |
|
29 |
#[post("/v1.0/delete_tag")]
|
30 |
+
async fn delete(model: web::Json<tag_info::Model>, data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
31 |
+
let _ = Mutation::delete_tag(&data.conn, model.tid).await?;
|
32 |
|
33 |
let json_response = JsonResponse {
|
34 |
code: 200,
|
|
|
38 |
|
39 |
Ok(HttpResponse::Ok()
|
40 |
.content_type("application/json")
|
41 |
+
.body(serde_json::to_string(&json_response)?))
|
42 |
}
|
43 |
|
44 |
+
#[get("/v1.0/tags", wrap = "HttpAuthentication::bearer(validator)")]
|
45 |
+
async fn list(data: web::Data<AppState>) -> Result<HttpResponse, AppError> {
|
46 |
+
let tags = Query::find_tag_infos(&data.conn).await?;
|
47 |
|
48 |
let mut result = HashMap::new();
|
49 |
result.insert("tags", tags);
|
|
|
56 |
|
57 |
Ok(HttpResponse::Ok()
|
58 |
.content_type("application/json")
|
59 |
+
.body(serde_json::to_string(&json_response)?))
|
60 |
}
|
src/api/user_info.rs
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
use actix_identity::Identity;
|
2 |
+
use actix_web::{get, HttpResponse, post, web};
|
3 |
+
use serde::{Deserialize, Serialize};
|
4 |
+
use crate::api::JsonResponse;
|
5 |
+
use crate::AppState;
|
6 |
+
use crate::entity::user_info::Model;
|
7 |
+
use crate::errors::{AppError, UserError};
|
8 |
+
use crate::service::user_info::Query;
|
9 |
+
|
10 |
+
pub(crate) fn create_auth_token(user: &Model) -> u64 {
|
11 |
+
use std::{
|
12 |
+
collections::hash_map::DefaultHasher,
|
13 |
+
hash::{Hash, Hasher},
|
14 |
+
};
|
15 |
+
|
16 |
+
let mut hasher = DefaultHasher::new();
|
17 |
+
user.hash(&mut hasher);
|
18 |
+
hasher.finish()
|
19 |
+
}
|
20 |
+
|
21 |
+
#[derive(Clone, Debug, Serialize, Deserialize)]
|
22 |
+
pub(crate) struct LoginParams {
|
23 |
+
pub(crate) email: String,
|
24 |
+
pub(crate) password: String,
|
25 |
+
}
|
26 |
+
|
27 |
+
#[post("/v1.0/login")]
|
28 |
+
async fn login(
|
29 |
+
data: web::Data<AppState>,
|
30 |
+
identity: Identity,
|
31 |
+
input: web::Json<LoginParams>
|
32 |
+
) -> Result<HttpResponse, AppError> {
|
33 |
+
match Query::login(&data.conn, &input.email, &input.password).await? {
|
34 |
+
Some(user) => {
|
35 |
+
let token = create_auth_token(&user).to_string();
|
36 |
+
|
37 |
+
identity.remember(token.clone());
|
38 |
+
|
39 |
+
let json_response = JsonResponse {
|
40 |
+
code: 200,
|
41 |
+
err: "".to_owned(),
|
42 |
+
data: token.clone(),
|
43 |
+
};
|
44 |
+
|
45 |
+
Ok(HttpResponse::Ok()
|
46 |
+
.content_type("application/json")
|
47 |
+
.append_header(("X-Auth-Token", token))
|
48 |
+
.body(serde_json::to_string(&json_response)?))
|
49 |
+
}
|
50 |
+
None => Err(UserError::LoginFailed.into())
|
51 |
+
}
|
52 |
+
}
|
src/entity/tag_info.rs
CHANGED
@@ -9,10 +9,10 @@ pub struct Model {
|
|
9 |
pub tid: i64,
|
10 |
pub uid: i64,
|
11 |
pub tag_name: String,
|
12 |
-
pub regx: String
|
13 |
pub color: i64,
|
14 |
pub icon: i64,
|
15 |
-
pub dir: String
|
16 |
|
17 |
#[serde(skip_deserializing)]
|
18 |
pub created_at: Date,
|
|
|
9 |
pub tid: i64,
|
10 |
pub uid: i64,
|
11 |
pub tag_name: String,
|
12 |
+
pub regx: Option<String>,
|
13 |
pub color: i64,
|
14 |
pub icon: i64,
|
15 |
+
pub dir: Option<String>,
|
16 |
|
17 |
#[serde(skip_deserializing)]
|
18 |
pub created_at: Date,
|
src/entity/user_info.rs
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
use sea_orm::entity::prelude::*;
|
2 |
use serde::{Deserialize, Serialize};
|
3 |
|
4 |
-
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)]
|
5 |
#[sea_orm(table_name = "user_info")]
|
6 |
pub struct Model {
|
7 |
#[sea_orm(primary_key)]
|
@@ -9,10 +9,11 @@ pub struct Model {
|
|
9 |
pub uid: i64,
|
10 |
pub email: String,
|
11 |
pub nickname: String,
|
12 |
-
pub avatar_url: String
|
13 |
pub color_schema: String,
|
14 |
pub list_style: String,
|
15 |
pub language: String,
|
|
|
16 |
|
17 |
#[serde(skip_deserializing)]
|
18 |
pub created_at: Date,
|
|
|
1 |
use sea_orm::entity::prelude::*;
|
2 |
use serde::{Deserialize, Serialize};
|
3 |
|
4 |
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, DeriveEntityModel, Deserialize, Serialize)]
|
5 |
#[sea_orm(table_name = "user_info")]
|
6 |
pub struct Model {
|
7 |
#[sea_orm(primary_key)]
|
|
|
9 |
pub uid: i64,
|
10 |
pub email: String,
|
11 |
pub nickname: String,
|
12 |
+
pub avatar_url: Option<String>,
|
13 |
pub color_schema: String,
|
14 |
pub list_style: String,
|
15 |
pub language: String,
|
16 |
+
pub password: String,
|
17 |
|
18 |
#[serde(skip_deserializing)]
|
19 |
pub created_at: Date,
|
src/errors.rs
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
use actix_web::{HttpResponse, ResponseError};
|
2 |
+
use thiserror::Error;
|
3 |
+
|
4 |
+
#[derive(Debug, Error)]
|
5 |
+
pub(crate) enum AppError {
|
6 |
+
#[error("`{0}`")]
|
7 |
+
User(#[from] UserError),
|
8 |
+
|
9 |
+
#[error("`{0}`")]
|
10 |
+
Json(#[from] serde_json::Error),
|
11 |
+
|
12 |
+
#[error("`{0}`")]
|
13 |
+
Actix(#[from] actix_web::Error),
|
14 |
+
|
15 |
+
#[error("`{0}`")]
|
16 |
+
Db(#[from] sea_orm::DbErr),
|
17 |
+
|
18 |
+
#[error("`{0}`")]
|
19 |
+
Std(#[from] std::io::Error),
|
20 |
+
}
|
21 |
+
|
22 |
+
#[derive(Debug, Error)]
|
23 |
+
pub(crate) enum UserError {
|
24 |
+
#[error("`username` field of `User` cannot be empty!")]
|
25 |
+
EmptyUsername,
|
26 |
+
|
27 |
+
#[error("`username` field of `User` cannot contain whitespaces!")]
|
28 |
+
UsernameInvalidCharacter,
|
29 |
+
|
30 |
+
#[error("`password` field of `User` cannot be empty!")]
|
31 |
+
EmptyPassword,
|
32 |
+
|
33 |
+
#[error("`password` field of `User` cannot contain whitespaces!")]
|
34 |
+
PasswordInvalidCharacter,
|
35 |
+
|
36 |
+
#[error("Could not find any `User` for id: `{0}`!")]
|
37 |
+
NotFound(i64),
|
38 |
+
|
39 |
+
#[error("Failed to login user!")]
|
40 |
+
LoginFailed,
|
41 |
+
|
42 |
+
#[error("User is not logged in!")]
|
43 |
+
NotLoggedIn,
|
44 |
+
|
45 |
+
#[error("Invalid authorization token!")]
|
46 |
+
InvalidToken,
|
47 |
+
|
48 |
+
#[error("Could not find any `User`!")]
|
49 |
+
Empty,
|
50 |
+
}
|
51 |
+
|
52 |
+
impl ResponseError for AppError {
|
53 |
+
fn status_code(&self) -> actix_web::http::StatusCode {
|
54 |
+
match self {
|
55 |
+
AppError::User(user_error) => match user_error {
|
56 |
+
UserError::EmptyUsername => actix_web::http::StatusCode::UNPROCESSABLE_ENTITY,
|
57 |
+
UserError::UsernameInvalidCharacter => {
|
58 |
+
actix_web::http::StatusCode::UNPROCESSABLE_ENTITY
|
59 |
+
}
|
60 |
+
UserError::EmptyPassword => actix_web::http::StatusCode::UNPROCESSABLE_ENTITY,
|
61 |
+
UserError::PasswordInvalidCharacter => {
|
62 |
+
actix_web::http::StatusCode::UNPROCESSABLE_ENTITY
|
63 |
+
}
|
64 |
+
UserError::NotFound(_) => actix_web::http::StatusCode::NOT_FOUND,
|
65 |
+
UserError::NotLoggedIn => actix_web::http::StatusCode::UNAUTHORIZED,
|
66 |
+
UserError::Empty => actix_web::http::StatusCode::NOT_FOUND,
|
67 |
+
UserError::LoginFailed => actix_web::http::StatusCode::NOT_FOUND,
|
68 |
+
UserError::InvalidToken => actix_web::http::StatusCode::UNAUTHORIZED,
|
69 |
+
},
|
70 |
+
AppError::Json(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
|
71 |
+
AppError::Actix(fail) => fail.as_response_error().status_code(),
|
72 |
+
AppError::Db(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
|
73 |
+
AppError::Std(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
fn error_response(&self) -> HttpResponse {
|
78 |
+
let status_code = self.status_code();
|
79 |
+
let response = HttpResponse::build(status_code).body(self.to_string());
|
80 |
+
response
|
81 |
+
}
|
82 |
+
}
|
src/main.rs
CHANGED
@@ -1,19 +1,41 @@
|
|
1 |
mod api;
|
2 |
mod entity;
|
3 |
mod service;
|
|
|
4 |
|
5 |
use std::env;
|
6 |
use actix_files::Files;
|
7 |
-
use
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
use listenfd::ListenFd;
|
9 |
use sea_orm::{Database, DatabaseConnection};
|
10 |
use migration::{Migrator, MigratorTrait};
|
|
|
11 |
|
12 |
#[derive(Debug, Clone)]
|
13 |
struct AppState {
|
14 |
conn: DatabaseConnection,
|
15 |
}
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
#[actix_web::main]
|
18 |
async fn main() -> std::io::Result<()> {
|
19 |
std::env::set_var("RUST_LOG", "debug");
|
@@ -39,6 +61,19 @@ async fn main() -> std::io::Result<()> {
|
|
39 |
App::new()
|
40 |
.service(Files::new("/static", "./static"))
|
41 |
.app_data(web::Data::new(state.clone()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
.wrap(middleware::Logger::default())
|
43 |
.configure(init)
|
44 |
});
|
@@ -55,7 +90,23 @@ async fn main() -> std::io::Result<()> {
|
|
55 |
}
|
56 |
|
57 |
fn init(cfg: &mut web::ServiceConfig) {
|
58 |
-
cfg.service(api::
|
59 |
-
cfg.service(api::
|
60 |
-
cfg.service(api::
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
|
|
1 |
mod api;
|
2 |
mod entity;
|
3 |
mod service;
|
4 |
+
mod errors;
|
5 |
|
6 |
use std::env;
|
7 |
use actix_files::Files;
|
8 |
+
use actix_identity::{CookieIdentityPolicy, IdentityService, RequestIdentity};
|
9 |
+
use actix_session::CookieSession;
|
10 |
+
use actix_web::{web, App, HttpServer, middleware, Error};
|
11 |
+
use actix_web::cookie::time::Duration;
|
12 |
+
use actix_web::dev::ServiceRequest;
|
13 |
+
use actix_web::error::ErrorUnauthorized;
|
14 |
+
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
15 |
use listenfd::ListenFd;
|
16 |
use sea_orm::{Database, DatabaseConnection};
|
17 |
use migration::{Migrator, MigratorTrait};
|
18 |
+
use crate::errors::UserError;
|
19 |
|
20 |
#[derive(Debug, Clone)]
|
21 |
struct AppState {
|
22 |
conn: DatabaseConnection,
|
23 |
}
|
24 |
|
25 |
+
pub(crate) async fn validator(
|
26 |
+
req: ServiceRequest,
|
27 |
+
credentials: BearerAuth,
|
28 |
+
) -> Result<ServiceRequest, Error> {
|
29 |
+
if let Some(token) = req.get_identity() {
|
30 |
+
println!("{}, {}",credentials.token(), token);
|
31 |
+
(credentials.token() == token)
|
32 |
+
.then(|| req)
|
33 |
+
.ok_or(ErrorUnauthorized(UserError::InvalidToken))
|
34 |
+
} else {
|
35 |
+
Err(ErrorUnauthorized(UserError::NotLoggedIn))
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
#[actix_web::main]
|
40 |
async fn main() -> std::io::Result<()> {
|
41 |
std::env::set_var("RUST_LOG", "debug");
|
|
|
61 |
App::new()
|
62 |
.service(Files::new("/static", "./static"))
|
63 |
.app_data(web::Data::new(state.clone()))
|
64 |
+
.wrap(IdentityService::new(
|
65 |
+
CookieIdentityPolicy::new(&[0; 32])
|
66 |
+
.name("auth-cookie")
|
67 |
+
.login_deadline(Duration::seconds(120))
|
68 |
+
.secure(false),
|
69 |
+
))
|
70 |
+
.wrap(
|
71 |
+
CookieSession::signed(&[0; 32])
|
72 |
+
.name("session-cookie")
|
73 |
+
.secure(false)
|
74 |
+
// WARNING(alex): This uses the `time` crate, not `std::time`!
|
75 |
+
.expires_in_time(Duration::seconds(60)),
|
76 |
+
)
|
77 |
.wrap(middleware::Logger::default())
|
78 |
.configure(init)
|
79 |
});
|
|
|
90 |
}
|
91 |
|
92 |
fn init(cfg: &mut web::ServiceConfig) {
|
93 |
+
cfg.service(api::tag_info::create);
|
94 |
+
cfg.service(api::tag_info::delete);
|
95 |
+
cfg.service(api::tag_info::list);
|
96 |
+
|
97 |
+
cfg.service(api::kb_info::create);
|
98 |
+
cfg.service(api::kb_info::delete);
|
99 |
+
cfg.service(api::kb_info::list);
|
100 |
+
|
101 |
+
cfg.service(api::doc_info::list);
|
102 |
+
cfg.service(api::doc_info::delete);
|
103 |
+
cfg.service(api::doc_info::mv);
|
104 |
+
cfg.service(api::doc_info::upload);
|
105 |
+
|
106 |
+
cfg.service(api::dialog_info::list);
|
107 |
+
cfg.service(api::dialog_info::delete);
|
108 |
+
cfg.service(api::dialog_info::detail);
|
109 |
+
cfg.service(api::dialog_info::create);
|
110 |
+
|
111 |
+
cfg.service(api::user_info::login);
|
112 |
}
|
src/service/dialog_info.rs
CHANGED
@@ -3,7 +3,7 @@ use sea_orm::{ActiveModelTrait, DbConn, DbErr, DeleteResult, EntityTrait, Pagina
|
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use sea_orm::QueryFilter;
|
5 |
use sea_orm::ColumnTrait;
|
6 |
-
use crate::entity::
|
7 |
use crate::entity::dialog_info::Entity;
|
8 |
|
9 |
pub struct Query;
|
|
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use sea_orm::QueryFilter;
|
5 |
use sea_orm::ColumnTrait;
|
6 |
+
use crate::entity::dialog_info;
|
7 |
use crate::entity::dialog_info::Entity;
|
8 |
|
9 |
pub struct Query;
|
src/service/doc_info.rs
CHANGED
@@ -1,9 +1,8 @@
|
|
1 |
use chrono::Local;
|
2 |
-
use postgres::fallible_iterator::FallibleIterator;
|
3 |
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryOrder};
|
4 |
use sea_orm::ActiveValue::Set;
|
5 |
use sea_orm::QueryFilter;
|
6 |
-
use crate::api::doc_info::
|
7 |
use crate::entity::{doc2_doc, doc_info, kb_info, tag_info};
|
8 |
use crate::entity::doc_info::Entity;
|
9 |
|
|
|
1 |
use chrono::Local;
|
|
|
2 |
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryOrder};
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use sea_orm::QueryFilter;
|
5 |
+
use crate::api::doc_info::Params;
|
6 |
use crate::entity::{doc2_doc, doc_info, kb_info, tag_info};
|
7 |
use crate::entity::doc_info::Entity;
|
8 |
|
src/service/kb_info.rs
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
use chrono::
|
2 |
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder};
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use crate::entity::kb_info;
|
|
|
1 |
+
use chrono::Local;
|
2 |
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder};
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use crate::entity::kb_info;
|
src/service/mod.rs
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
pub(crate) mod dialog_info;
|
2 |
pub(crate) mod tag_info;
|
3 |
pub(crate) mod kb_info;
|
4 |
-
pub(crate) mod doc_info;
|
|
|
|
1 |
pub(crate) mod dialog_info;
|
2 |
pub(crate) mod tag_info;
|
3 |
pub(crate) mod kb_info;
|
4 |
+
pub(crate) mod doc_info;
|
5 |
+
pub(crate) mod user_info;
|
src/service/tag_info.rs
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
use chrono::
|
2 |
use sea_orm::{ActiveModelTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryOrder};
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use crate::entity::tag_info;
|
|
|
1 |
+
use chrono::Local;
|
2 |
use sea_orm::{ActiveModelTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryOrder};
|
3 |
use sea_orm::ActiveValue::Set;
|
4 |
use crate::entity::tag_info;
|
src/service/user_info.rs
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
use chrono::Local;
|
2 |
+
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, DeleteResult, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder};
|
3 |
+
use sea_orm::ActiveValue::Set;
|
4 |
+
use crate::entity::user_info;
|
5 |
+
use crate::entity::user_info::Entity;
|
6 |
+
|
7 |
+
pub struct Query;
|
8 |
+
|
9 |
+
impl Query {
|
10 |
+
pub async fn find_user_info_by_id(db: &DbConn, id: i64) -> Result<Option<user_info::Model>, DbErr> {
|
11 |
+
Entity::find_by_id(id).one(db).await
|
12 |
+
}
|
13 |
+
|
14 |
+
pub async fn login(db: &DbConn, email: &str, password: &str) -> Result<Option<user_info::Model>, DbErr> {
|
15 |
+
Entity::find()
|
16 |
+
.filter(user_info::Column::Email.eq(email))
|
17 |
+
.filter(user_info::Column::Password.eq(password))
|
18 |
+
.one(db)
|
19 |
+
.await
|
20 |
+
}
|
21 |
+
|
22 |
+
pub async fn find_user_infos(db: &DbConn) -> Result<Vec<user_info::Model>, DbErr> {
|
23 |
+
Entity::find().all(db).await
|
24 |
+
}
|
25 |
+
|
26 |
+
pub async fn find_user_infos_in_page(
|
27 |
+
db: &DbConn,
|
28 |
+
page: u64,
|
29 |
+
posts_per_page: u64,
|
30 |
+
) -> Result<(Vec<user_info::Model>, u64), DbErr> {
|
31 |
+
// Setup paginator
|
32 |
+
let paginator = Entity::find()
|
33 |
+
.order_by_asc(user_info::Column::Uid)
|
34 |
+
.paginate(db, posts_per_page);
|
35 |
+
let num_pages = paginator.num_pages().await?;
|
36 |
+
|
37 |
+
// Fetch paginated posts
|
38 |
+
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
pub struct Mutation;
|
43 |
+
|
44 |
+
impl Mutation {
|
45 |
+
pub async fn create_user(
|
46 |
+
db: &DbConn,
|
47 |
+
form_data: user_info::Model,
|
48 |
+
) -> Result<user_info::ActiveModel, DbErr> {
|
49 |
+
user_info::ActiveModel {
|
50 |
+
uid: Default::default(),
|
51 |
+
email: Set(form_data.email.to_owned()),
|
52 |
+
nickname: Set(form_data.nickname.to_owned()),
|
53 |
+
avatar_url: Set(form_data.avatar_url.to_owned()),
|
54 |
+
color_schema: Set(form_data.color_schema.to_owned()),
|
55 |
+
list_style: Set(form_data.list_style.to_owned()),
|
56 |
+
language: Set(form_data.language.to_owned()),
|
57 |
+
password: Set(form_data.password.to_owned()),
|
58 |
+
created_at: Set(Local::now().date_naive()),
|
59 |
+
updated_at: Set(Local::now().date_naive()),
|
60 |
+
}
|
61 |
+
.save(db)
|
62 |
+
.await
|
63 |
+
}
|
64 |
+
|
65 |
+
pub async fn update_tag_by_id(
|
66 |
+
db: &DbConn,
|
67 |
+
id: i64,
|
68 |
+
form_data: user_info::Model,
|
69 |
+
) -> Result<user_info::Model, DbErr> {
|
70 |
+
let user: user_info::ActiveModel = Entity::find_by_id(id)
|
71 |
+
.one(db)
|
72 |
+
.await?
|
73 |
+
.ok_or(DbErr::Custom("Cannot find tag.".to_owned()))
|
74 |
+
.map(Into::into)?;
|
75 |
+
|
76 |
+
user_info::ActiveModel {
|
77 |
+
uid: user.uid,
|
78 |
+
email: Set(form_data.email.to_owned()),
|
79 |
+
nickname: Set(form_data.nickname.to_owned()),
|
80 |
+
avatar_url: Set(form_data.avatar_url.to_owned()),
|
81 |
+
color_schema: Set(form_data.color_schema.to_owned()),
|
82 |
+
list_style: Set(form_data.list_style.to_owned()),
|
83 |
+
language: Set(form_data.language.to_owned()),
|
84 |
+
password: Set(form_data.password.to_owned()),
|
85 |
+
created_at: Default::default(),
|
86 |
+
updated_at: Set(Local::now().date_naive()),
|
87 |
+
}
|
88 |
+
.update(db)
|
89 |
+
.await
|
90 |
+
}
|
91 |
+
|
92 |
+
pub async fn delete_tag(db: &DbConn, tid: i64) -> Result<DeleteResult, DbErr> {
|
93 |
+
let tag: user_info::ActiveModel = Entity::find_by_id(tid)
|
94 |
+
.one(db)
|
95 |
+
.await?
|
96 |
+
.ok_or(DbErr::Custom("Cannot find tag.".to_owned()))
|
97 |
+
.map(Into::into)?;
|
98 |
+
|
99 |
+
tag.delete(db).await
|
100 |
+
}
|
101 |
+
|
102 |
+
pub async fn delete_all_tags(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
103 |
+
Entity::delete_many().exec(db).await
|
104 |
+
}
|
105 |
+
}
|