• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

doitsu2014 / my-cms / 14187034714

01 Apr 2025 04:12AM UTC coverage: 59.597% (+20.5%) from 39.058%
14187034714

push

github

web-flow
Feature/support multi language (#19)

* Enhance entity structure: add category and post translations, update migration dependencies, and improve README guidelines

* Add support for category translations: update create and modify handlers, requests, and tests

add TODO

* Add category translations support: update create, modify, and read handlers, and adjust request structures

* Refactor category translation requests: remove slug field and update handlers to set category ID for translations

* Add support for post translations: update create and modify requests, handlers, and models

* Update CI configuration and scripts for improved coverage reporting and toolchain management

* Update coverage configuration and scripts for improved reporting and toolchain management

* Update CI and coverage configurations for improved reporting and ignore patterns

* Update CI configuration and coverage scripts for improved reporting and cleanup

* Remove unused coverage step from CI configuration

* Update CI configuration to use fixed lcov report paths for coverage uploads

197 of 396 new or added lines in 19 files covered. (49.75%)

71 existing lines in 11 files now uncovered.

975 of 1636 relevant lines covered (59.6%)

26.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.7
/application_core/src/commands/category/create/create_handler.rs
1
use std::sync::Arc;
2

3
use super::create_request::CreateCategoryRequest;
4
use crate::{
5
    commands::tag::create::create_handler::{TagCreateHandler, TagCreateHandlerTrait},
6
    common::{app_error::AppError, datetime_generator::generate_vietnam_now},
7
    entities::{categories, category_tags, category_translations},
8
    Categories,
9
};
10
use sea_orm::{
11
    DatabaseConnection, EntityTrait, IntoActiveModel, TransactionError, TransactionTrait,
12
};
13
use tracing::instrument;
14
use uuid::Uuid;
15

16
pub trait CategoryCreateHandlerTrait {
17
    fn handle_create_category_with_tags(
18
        &self,
19
        body: CreateCategoryRequest,
20
        actor_email: Option<String>,
21
    ) -> impl std::future::Future<Output = Result<Uuid, AppError>>;
22
}
23

24
#[derive(Debug)]
25
pub struct CategoryCreateHandler {
26
    pub db: Arc<DatabaseConnection>,
27
}
28

29
impl CategoryCreateHandlerTrait for CategoryCreateHandler {
30
    #[instrument]
31
    async fn handle_create_category_with_tags(
32
        &self,
33
        body: CreateCategoryRequest,
34
        actor_email: Option<String>,
35
    ) -> Result<Uuid, AppError> {
36
        let tag_create_handler = TagCreateHandler {
37
            db: self.db.clone(),
38
        };
39

40
        // Prepare Category
41
        let model: categories::Model = body.into_model();
42
        let model = categories::Model {
43
            created_by: actor_email.clone().unwrap_or("System".to_string()),
44
            created_at: generate_vietnam_now(),
45
            ..model
46
        };
47

48
        // Prepare Category Active Model
49
        let create_category = categories::ActiveModel {
50
            ..model.into_active_model()
51
        };
52

53
        // Prepare Tags
54
        let tags: Vec<String> = body.tag_names.unwrap_or_default();
55

56
        // Prepare Translations
57
        let translations = body.translations.unwrap_or_default();
58

59
        // Execute Transaction to Insert Category, Tags, and Translations
60
        let result: Result<Uuid, TransactionError<AppError>> = self
61
            .db
62
            .as_ref()
63
            .transaction::<_, Uuid, AppError>(|tx| {
23✔
64
                Box::pin(async move {
23✔
65
                    // Insert New Tags
66
                    let create_tags_response = tag_create_handler
23✔
67
                        .handle_create_tags_in_transaction(tags, actor_email.clone(), tx)
23✔
68
                        .await?;
23✔
69

70
                    // Combine New Tag Ids and Existing Tag Ids
71
                    let all_tag_ids = create_tags_response
23✔
72
                        .existing_tag_ids
23✔
73
                        .into_iter()
23✔
74
                        .chain(create_tags_response.new_tag_ids)
23✔
75
                        .collect::<Vec<Uuid>>();
23✔
76

77
                    // Insert Category
78
                    let inserted_category = Categories::insert(create_category)
23✔
79
                        .exec(tx)
23✔
80
                        .await
23✔
81
                        .map_err(|e| e.into())?;
23✔
82

83
                    // Insert Category Tags
84
                    if !all_tag_ids.is_empty() {
23✔
85
                        let category_tags = all_tag_ids
21✔
86
                            .iter()
21✔
87
                            .map(|tag_id| {
78✔
88
                                category_tags::Model {
78✔
89
                                    category_id: inserted_category.last_insert_id,
78✔
90
                                    tag_id: tag_id.to_owned(),
78✔
91
                                }
78✔
92
                                .into_active_model()
78✔
93
                            })
78✔
94
                            .collect::<Vec<category_tags::ActiveModel>>();
21✔
95

21✔
96
                        category_tags::Entity::insert_many(category_tags)
21✔
97
                            .exec(tx)
21✔
98
                            .await
21✔
99
                            .map_err(|e| e.into())?;
21✔
100
                    }
2✔
101

102
                    // Insert Category Translations
103
                    if !translations.is_empty() {
23✔
NEW
104
                        let category_translations = translations
×
NEW
105
                            .into_iter()
×
NEW
106
                            .map(|translation| {
×
NEW
107
                                category_translations::Model {
×
NEW
108
                                    category_id: inserted_category.last_insert_id,
×
NEW
109
                                    ..translation.into_model()
×
NEW
110
                                }
×
NEW
111
                                .into_active_model()
×
NEW
112
                            })
×
NEW
113
                            .collect::<Vec<category_translations::ActiveModel>>();
×
NEW
114

×
NEW
115
                        category_translations::Entity::insert_many(category_translations)
×
NEW
116
                            .exec(tx)
×
NEW
117
                            .await
×
NEW
118
                            .map_err(|e| e.into())?;
×
119
                    }
23✔
120

121
                    Ok(inserted_category.last_insert_id)
23✔
122
                })
23✔
123
            })
23✔
124
            .await;
125

126
        match result {
127
            Ok(inserted_id) => Ok(inserted_id),
128
            Err(e) => Err(e.into()),
129
        }
130
    }
131
}
132

133
#[cfg(test)]
134
pub mod tests {
135
    use std::sync::Arc;
136
    use test_helpers::{setup_test_space, ContainerAsyncPostgresEx};
137

138
    use crate::commands::category::{
139
        create::create_handler::CategoryCreateHandlerTrait,
140
        read::category_read_handler::{CategoryReadHandler, CategoryReadHandlerTrait},
141
        test::{fake_create_category_request, fake_create_category_request_as_child},
142
    };
143

144
    #[async_std::test]
145
    async fn handle_create_cartegory_testcase_01() {
146
        let beginning_test_timestamp = chrono::Utc::now();
147
        let test_space = setup_test_space().await;
148
        let database = test_space.postgres.get_database_connection().await;
149
        let number_of_tags = 5;
150
        let request = fake_create_category_request(number_of_tags);
151

152
        let create_handler = super::CategoryCreateHandler {
153
            db: Arc::new(database.clone()),
154
        };
155
        let read_handler = CategoryReadHandler {
156
            db: Arc::new(database),
157
        };
158

159
        let result = create_handler
160
            .handle_create_category_with_tags(request, None)
161
            .await
162
            .unwrap();
163

164
        assert!(!result.is_nil());
165

166
        let category_in_db = read_handler.handle_get_all_categories().await.unwrap();
167
        let first = &category_in_db.first().unwrap();
168
        assert_eq!(result, first.id);
169
        assert!(first.created_by == "System");
170
        assert!(first.created_at >= beginning_test_timestamp);
171
        assert!(first.row_version == 1);
172
        assert!(first.tags.len() == number_of_tags);
173
    }
174

175
    #[async_std::test]
176
    async fn handle_create_cartegory_testcase_parent() {
177
        let test_space = setup_test_space().await;
178
        let conn = test_space.postgres.get_database_connection().await;
179
        let number_of_tags = 5;
180

181
        let create_handler = super::CategoryCreateHandler {
182
            db: Arc::new(conn.clone()),
183
        };
184
        let read_handler = CategoryReadHandler { db: Arc::new(conn) };
185
        let parent_request = fake_create_category_request(number_of_tags);
186
        let parent_id = create_handler
187
            .handle_create_category_with_tags(parent_request, None)
188
            .await
189
            .unwrap();
190
        let child_request = fake_create_category_request_as_child(parent_id, number_of_tags);
191
        let child = create_handler
192
            .handle_create_category_with_tags(child_request, None)
193
            .await
194
            .unwrap();
195
        let categories_in_db = read_handler.handle_get_all_categories().await.unwrap();
196
        let first = categories_in_db
197
            .iter()
198
            .find(|x| x.parent_id.is_none())
2✔
199
            .unwrap();
200
        let child_instance = categories_in_db.iter().find(|x| x.id == child).unwrap();
1✔
201
        assert_eq!(child_instance.parent_id.unwrap(), first.id);
202
    }
203
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc