Skip to content

Commit bf191e3

Browse files
committed
feat: add distribution backend
1 parent 5b18ea3 commit bf191e3

13 files changed

Lines changed: 251 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE IF NOT EXISTS distributions (
2+
address TEXT NOT NULL,
3+
badge_name TEXT NOT NULL,
4+
distribution_id TEXT NOT NULL
5+
);

backend/src/application/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod create_profile;
22
pub mod create_project;
33
pub mod delete_project;
44
pub mod login;
5+
pub mod register_distribution;
56
pub mod sync_github_issues;
67
pub mod update_profile;
78
pub mod update_project;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::sync::Arc;
2+
3+
use crate::{
4+
application::dtos::distribution_dtos::RegisterDistributionRequest,
5+
domain::repositories::distribution_repository::{DistributionRecord, DistributionRepository},
6+
};
7+
8+
pub async fn register_distribution(
9+
repository: Arc<dyn DistributionRepository>,
10+
request: RegisterDistributionRequest,
11+
) -> Result<(), String> {
12+
if request.distributions.is_empty() {
13+
return Err("distributions must not be empty".to_string());
14+
}
15+
16+
let records: Vec<DistributionRecord> = request
17+
.distributions
18+
.into_iter()
19+
.map(|item| DistributionRecord {
20+
address: item.address,
21+
badge_name: item.badge_name,
22+
distribution_id: item.distribution_id,
23+
})
24+
.collect();
25+
26+
repository
27+
.create_many(&records)
28+
.await
29+
.map_err(|e| e.to_string())
30+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Debug, Deserialize, Serialize, Clone)]
4+
pub struct RegisterDistributionItem {
5+
pub address: String,
6+
#[serde(rename = "badgeName")]
7+
pub badge_name: String,
8+
#[serde(rename = "distributionId")]
9+
pub distribution_id: String,
10+
}
11+
12+
#[derive(Debug, Deserialize, Serialize, Clone)]
13+
pub struct RegisterDistributionRequest {
14+
pub distributions: Vec<RegisterDistributionItem>,
15+
}

backend/src/application/dtos/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod auth_dtos;
2+
pub mod distribution_dtos;
23
pub mod github_dtos;
34
pub mod profile_dtos;
45
pub mod project_dtos;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use async_trait::async_trait;
2+
3+
#[derive(Clone, Debug)]
4+
pub struct DistributionRecord {
5+
pub address: String,
6+
pub badge_name: String,
7+
pub distribution_id: String,
8+
}
9+
10+
#[async_trait]
11+
pub trait DistributionRepository: Send + Sync {
12+
async fn create_many(
13+
&self,
14+
records: &[DistributionRecord],
15+
) -> Result<(), Box<dyn std::error::Error>>;
16+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
pub mod distribution_repository;
12
pub mod github_issue_repository;
23
pub mod profile_repository;
34
pub mod project_repository;
45

6+
pub use distribution_repository::DistributionRepository;
57
pub use github_issue_repository::GithubIssueRepository;
68
pub use profile_repository::ProfileRepository;
79
pub use project_repository::ProjectRepository;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
pub mod postgres_distribution_repository;
12
pub mod postgres_github_issue_repository;
23
pub mod postgres_profile_repository;
34
pub mod postgres_project_repository;
45

6+
pub use postgres_distribution_repository::PostgresDistributionRepository;
57
pub use postgres_github_issue_repository::PostgresGithubIssueRepository;
68
pub use postgres_profile_repository::PostgresProfileRepository;
79
pub use postgres_project_repository::PostgresProjectRepository;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use async_trait::async_trait;
2+
use sqlx::PgPool;
3+
4+
use crate::domain::repositories::distribution_repository::{
5+
DistributionRecord, DistributionRepository,
6+
};
7+
8+
#[derive(Clone)]
9+
pub struct PostgresDistributionRepository {
10+
pool: PgPool,
11+
}
12+
13+
impl PostgresDistributionRepository {
14+
pub fn new(pool: PgPool) -> Self {
15+
Self { pool }
16+
}
17+
}
18+
19+
#[async_trait]
20+
impl DistributionRepository for PostgresDistributionRepository {
21+
async fn create_many(
22+
&self,
23+
records: &[DistributionRecord],
24+
) -> Result<(), Box<dyn std::error::Error>> {
25+
let mut tx = self.pool.begin().await?;
26+
27+
for record in records {
28+
sqlx::query(
29+
r#"
30+
INSERT INTO distributions (address, badge_name, distribution_id)
31+
VALUES ($1, $2, $3)
32+
"#,
33+
)
34+
.bind(&record.address)
35+
.bind(&record.badge_name)
36+
.bind(&record.distribution_id)
37+
.execute(&mut *tx)
38+
.await?;
39+
}
40+
41+
tx.commit().await?;
42+
Ok(())
43+
}
44+
}

backend/src/presentation/api.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use std::sync::Arc;
22

3-
use crate::domain::repositories::{GithubIssueRepository, ProfileRepository, ProjectRepository};
3+
use crate::domain::repositories::{
4+
DistributionRepository, GithubIssueRepository, ProfileRepository, ProjectRepository,
5+
};
46
use crate::domain::services::auth_service::AuthService;
57
use crate::domain::services::github_service::GithubService;
68
use crate::infrastructure::{
79
repositories::{
10+
postgres_distribution_repository::PostgresDistributionRepository,
811
postgres_github_issue_repository::PostgresGithubIssueRepository,
912
postgres_project_repository::PostgresProjectRepository, PostgresProfileRepository,
1013
},
@@ -43,6 +46,7 @@ use super::handlers::{
4346
list_github_issues_handler,
4447
list_projects_handler,
4548
login_handler,
49+
register_distribution_handler,
4650
update_profile_handler,
4751
update_project_handler,
4852
};
@@ -52,13 +56,15 @@ use super::middlewares::{admin_auth_layer, eth_auth_layer, test_auth_layer};
5256
pub async fn create_app(pool: sqlx::PgPool) -> Router {
5357
let profile_repository = Arc::from(PostgresProfileRepository::new(pool.clone()));
5458
let project_repository = Arc::from(PostgresProjectRepository::new(pool.clone()));
59+
let distribution_repository = Arc::from(PostgresDistributionRepository::new(pool.clone()));
5560
let github_issue_repository = Arc::from(PostgresGithubIssueRepository::new(pool));
5661
let auth_service = EthereumAddressVerificationService::new(profile_repository.clone());
5762
let github_service: Arc<dyn GithubService> = Arc::from(RestGithubService::new());
5863

5964
let state: AppState = AppState {
6065
profile_repository,
6166
project_repository,
67+
distribution_repository,
6268
auth_service: Arc::from(auth_service),
6369
github_issue_repository,
6470
github_service,
@@ -76,6 +82,7 @@ pub async fn create_app(pool: sqlx::PgPool) -> Router {
7682
.route("/projects", post(create_project_handler))
7783
.route("/projects/:id", patch(update_project_handler))
7884
.route("/projects/:id", delete(delete_project_handler))
85+
.route("/distributions", post(register_distribution_handler))
7986
.with_state(state.clone());
8087

8188
let protected_with_auth = if std::env::var("TEST_MODE").is_ok() {
@@ -142,6 +149,7 @@ pub async fn create_app(pool: sqlx::PgPool) -> Router {
142149
pub struct AppState {
143150
pub profile_repository: Arc<dyn ProfileRepository>,
144151
pub project_repository: Arc<dyn ProjectRepository>,
152+
pub distribution_repository: Arc<dyn DistributionRepository>,
145153
pub auth_service: Arc<dyn AuthService>,
146154
pub github_issue_repository: Arc<dyn GithubIssueRepository>,
147155
pub github_service: Arc<dyn GithubService>,
@@ -159,6 +167,7 @@ pub fn test_api(state: AppState) -> Router {
159167
.route("/projects", post(create_project_handler))
160168
.route("/projects/:id", patch(update_project_handler))
161169
.route("/projects/:id", delete(delete_project_handler))
170+
.route("/distributions", post(register_distribution_handler))
162171
.with_state(state.clone())
163172
.layer(from_fn(test_auth_layer));
164173

0 commit comments

Comments
 (0)