Skip to content

Commit 37bb8c0

Browse files
committed
feat: add new modules for service and openapi
1 parent af66601 commit 37bb8c0

File tree

13 files changed

+377
-13
lines changed

13 files changed

+377
-13
lines changed

Cargo.lock

+62
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ members = [
1414
"crates/jz-migration",
1515
"crates/jz-model",
1616
"crates/jz-module",
17-
"crates/jz-openapi",
17+
"crates/jz-openapi", "crates/jz-service",
1818
"crates/jz-smart",
1919
"crates/jz-ssh",
2020
"crates/jz-stream",

crates/jz-api/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,7 @@ workspace = true
4646
workspace = true
4747

4848
[dependencies.jz-smart]
49+
workspace = true
50+
51+
[dependencies.jz-openapi]
4952
workspace = true

crates/jz-api/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl Api {
5959
.route("/", actix_web::web::get().to(|| async { "Hello World!" }))
6060
.service(scope("/api").configure(v1::v1_route))
6161
.service(scope("/git").configure(jz_smart::git_router))
62+
.service(scope("/openapi").configure(jz_openapi::openapi_router))
6263
})
6364
.bind(format!("0.0.0.0:{}", PROTS.to_string()))
6465
.context("Failed to apply actix settings")?

crates/jz-module/src/repo/list.rs

+73
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
1+
use sea_orm::*;
2+
use serde::{Deserialize, Serialize};
13
use serde_json::{json, Value};
24
use uuid::Uuid;
5+
use jz_model::repository;
36
use crate::AppModule;
47

8+
#[derive(Deserialize,Serialize)]
9+
pub struct RepositoryListParam {
10+
pub r#type: String,
11+
pub limit: Option<i64>,
12+
pub offset: Option<i64>,
13+
}
14+
#[derive(Deserialize,Serialize)]
15+
pub struct RepositoryListResult {
16+
creator: String, // owner name
17+
description: Option<String>,
18+
id: Uuid,
19+
image: Option<String>,
20+
runs: Option<i32>,
21+
size: Option<String>,
22+
r#type: String,
23+
}
24+
525
impl AppModule {
626
pub async fn repo_list_info(&self,ops_uid: Option<Uuid>, owner_name: String) -> anyhow::Result<Vec<Value>> {
727
let repos = self.repo_info_by_owner(owner_name).await?;
@@ -35,4 +55,57 @@ impl AppModule {
3555
}
3656
Ok(result)
3757
}
58+
pub async fn repo_list(&self, parma: RepositoryListParam) -> anyhow::Result<serde_json::Value> {
59+
let rtype = if parma.r#type == "all" {
60+
None
61+
} else {
62+
let rf = parma.r#type.to_lowercase();
63+
if rf == "code" {
64+
Some("Code".to_string())
65+
}else if rf == "data" {
66+
Some("Data".to_string())
67+
}else if rf == "model" {
68+
Some("Model".to_string())
69+
}else {
70+
return Err(anyhow::anyhow!("invalid rtype"));
71+
}
72+
};
73+
let mut condition = Condition::all()
74+
.add(repository::Column::IsPrivate.eq(false));
75+
if let Some(ref rtype) = rtype {
76+
condition = condition.add(repository::Column::Rtype.eq(rtype));
77+
};
78+
let repos = repository::Entity::find()
79+
.filter(condition)
80+
.order_by_desc(repository::Column::CreatedAt)
81+
.limit(parma.limit.unwrap_or(20) as u64)
82+
.offset(parma.offset.unwrap_or(0) as u64)
83+
.all(&self.read)
84+
.await?;
85+
let mut result: Vec<RepositoryListResult> = Vec::new();
86+
for i in repos {
87+
result.push(RepositoryListResult {
88+
creator: i.owner_name,
89+
description: i.description,
90+
id: i.uid,
91+
image: None,
92+
runs: None,
93+
size: None,
94+
r#type: i.rtype,
95+
});
96+
}
97+
let total = repository::Entity::find()
98+
.filter(repository::Column::Rtype.eq(parma.r#type))
99+
.filter(repository::Column::IsPrivate.eq(false))
100+
.count(&self.read)
101+
.await?;
102+
Ok(json!({
103+
"data": result,
104+
"limit": parma.limit,
105+
"offset": parma.offset,
106+
"total": total,
107+
"type": rtype,
108+
}))
109+
110+
}
38111
}

crates/jz-module/src/users/token.rs

+8
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,12 @@ impl AppModule {
132132
.await
133133
.map_err(|e| anyhow::anyhow!("{}", e))?)
134134
}
135+
pub async fn token_find(&self, token: String) -> anyhow::Result<token::Model> {
136+
token::Entity::find()
137+
.filter(token::Column::Token.eq(token))
138+
.one(&self.read)
139+
.await
140+
.map_err(|e| anyhow::anyhow!("{}", e))?
141+
.ok_or(anyhow::anyhow!("token not found"))
142+
}
135143
}

crates/jz-openapi/Cargo.toml

+35
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,38 @@ description.workspace = true
1212
homepage.workspace = true
1313

1414
[dependencies]
15+
actix-web = { version = "4", features = ["cookies"] }
16+
actix-session = { version = "0.10.1", features = ["redis-pool","redis-session"] }
17+
actix-files = { version = "0.6.6", features = ["tokio-uring"] }
18+
actix-multipart = { version = "0.7.2", features = ["derive"] }
19+
actix-web-lab = { version = "0.24.1", features = ["derive"] }
20+
actix-settings = { version = "0.8.0", features = [] }
21+
actix-web-httpauth = { version = "0.8.2", features = [] }
22+
23+
tokio = { version = "1", features = ["full"] }
24+
25+
serde = { version = "1", features = ["derive"] }
26+
serde_json = { version = "1", features = ["raw_value"] }
27+
uuid = { version = "1"}
28+
chrono = { version = "0.4"}
29+
30+
anyhow = { version = "1", features = ["backtrace"] }
31+
32+
captcha-rs = { version = "0.2.11", features = [] }
33+
log = "0.4.26"
34+
lazy_static = "1.5.0"
35+
sha256 = { version = "1.6.0", features = [] }
36+
[dependencies.jz-module]
37+
workspace = true
38+
39+
[dependencies.jz-model]
40+
workspace = true
41+
42+
[dependencies.jz-git]
43+
workspace = true
44+
45+
[dependencies.jz-dragonfly]
46+
workspace = true
47+
48+
[dependencies.jz-smart]
49+
workspace = true

crates/jz-openapi/src/bare.rs

Whitespace-only changes.

crates/jz-openapi/src/lib.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
pub fn add(left: u64, right: u64) -> u64 {
2-
left + right
3-
}
1+
use actix_web::web::{get, scope};
2+
use crate::repo::repo_list;
43

5-
#[cfg(test)]
6-
mod tests {
7-
use super::*;
4+
pub mod repo;
5+
pub mod bare;
86

9-
#[test]
10-
fn it_works() {
11-
let result = add(2, 2);
12-
assert_eq!(result, 4);
13-
}
14-
}
7+
pub fn openapi_router(cfg: &mut actix_web::web::ServiceConfig) {
8+
cfg
9+
.service(
10+
scope("/repo")
11+
.route("",get().to(repo_list))
12+
)
13+
;
14+
}

crates/jz-openapi/src/repo.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use actix_web::web::Data;
2+
use actix_web_httpauth::extractors::bearer::BearerAuth;
3+
use jz_module::AppModule;
4+
use jz_module::repo::list::RepositoryListParam;
5+
6+
pub async fn repo_list(
7+
service: Data<AppModule>,
8+
query: actix_web::web::Query<RepositoryListParam>,
9+
credentials: Option<BearerAuth>,
10+
)
11+
-> actix_web::Result<actix_web::HttpResponse>
12+
{
13+
let Some(credentials) = credentials else {
14+
return Ok(actix_web::HttpResponse::Unauthorized().body("token invalid"))
15+
};
16+
let Ok(token) = service.token_find(credentials.token().to_string()).await else {
17+
return Ok(actix_web::HttpResponse::Unauthorized().body("token invalid"))
18+
};
19+
let _access = token.access;
20+
let result = service.repo_list(query.into_inner()).await;
21+
match result {
22+
Ok(data) => {
23+
Ok(actix_web::HttpResponse::Ok().json(data))
24+
}
25+
Err(err) => {
26+
Ok(actix_web::HttpResponse::InternalServerError().body(err.to_string()))
27+
}
28+
}
29+
}

crates/jz-service/Cargo.toml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[package]
2+
name = "jz-service"
3+
version = "0.1.0"
4+
edition.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
documentation.workspace = true
8+
readme.workspace = true
9+
keywords.workspace = true
10+
categories.workspace = true
11+
description.workspace = true
12+
homepage.workspace = true
13+
14+
[dependencies]
15+
jz-model = { workspace = true }
16+
serde = { version = "1", features = ["derive"] }
17+
sea-orm = { version = "1", features = ["sqlx-all", "runtime-tokio"] }
18+
uuid = { version = "1", features = ["v7","v4"] }
19+
chrono = { version = "0.4", features = ["clock","serde"] }
20+
tokio = { version = "1", features = ["full"] }
21+
dotenv = { version = "0.15.0" ,features = [] }
22+
anyhow = { version = "1", features = ["backtrace"] }
23+
sha256 = { version = "1", features = ["tokio"] }
24+
serde_json = "1.0.140"
25+
log = "0.4.26"
26+
rand = "0.8.5"
27+
28+
29+
[dependencies.jz-git]
30+
workspace = true
31+
32+
[dependencies.jz-jobs]
33+
workspace = true
34+
35+
[dependencies.jz-email]
36+
workspace = true
37+
38+
[dependencies.jz-dragonfly]
39+
workspace = true

crates/jz-service/src/container.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use std::any::Any;
2+
use std::sync::{Arc, Mutex};
3+
4+
#[derive(Debug, Clone)]
5+
pub struct ContainerIOC {
6+
inner: Arc<Mutex<Vec<Box<dyn Send + Sync + 'static + Any>>>>,
7+
}
8+
9+
impl ContainerIOC {
10+
pub async fn init() -> ContainerIOC {
11+
Self {
12+
inner: Arc::new(Mutex::new(vec![])),
13+
}
14+
}
15+
16+
pub async fn take<T: 'static>(&self) -> Option<Arc<T>> {
17+
let inner = self.inner.lock().unwrap();
18+
for item in inner.iter() {
19+
if let Some(arc_item) = item.downcast_ref::<Arc<T>>() {
20+
return Some(arc_item.clone());
21+
}
22+
}
23+
drop(inner);
24+
None
25+
}
26+
27+
pub fn inject<T: 'static + Send + Sync>(&self, item: T) {
28+
let mut inner = self.inner.lock().unwrap();
29+
inner.push(Box::new(Arc::new(item)));
30+
drop(inner);
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use super::*;
37+
38+
#[tokio::test]
39+
async fn test_ioc() {
40+
let ioc = ContainerIOC::init().await;
41+
ioc.inject("str".to_string());
42+
ioc.inject(2_i32);
43+
assert_eq!(
44+
ioc.take::<String>().await,
45+
Some(Arc::new("str".to_string()))
46+
);
47+
assert_eq!(ioc.take::<i32>().await, Some(Arc::new(2_i32)));
48+
}
49+
}

0 commit comments

Comments
 (0)