-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add batch processing and multiple new features #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -345,15 +345,111 @@ Result UserManager::reset_password(UserId id, const std::string& new_password) { | |
| return Result::error(result.error_code(), result.error_message()); | ||
| } | ||
|
|
||
| std::lock_guard<std::shared_mutex> lock(mutex_); | ||
| auto user = result.value(); | ||
|
|
||
| User* user = result.value(); | ||
| std::string new_salt = User::generate_salt(); | ||
| user->security().password_hash = User::hash_password(new_password, new_salt); | ||
| user->security().password_salt = new_salt; | ||
|
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
| Result UserManager::force_password_reset(UserId id) { | ||
| auto result = get_user(id); | ||
| if (!result) { | ||
| return Result::error(result.error_code(), result.error_message()); | ||
| } | ||
| result.value()->security().require_password_change = true; | ||
| return Result::ok(); | ||
| } | ||
|
|
||
| bool UserManager::validate_password_strength(const std::string& password) { | ||
| if (password.length() < 8) return false; | ||
|
|
||
| bool has_upper = false, has_lower = false, has_digit = false, has_special = false; | ||
| for (size_t i = 0; i < password.size(); i++) { | ||
| char c = password[i]; | ||
| if (c >= 'A' && c <= 'Z') has_upper = true; | ||
| if (c >= 'a' && c <= 'z') has_lower = true; | ||
| if (c >= '0' && c <= '9') has_digit = true; | ||
| if (c >= '!' && c <= '/') has_special = true; | ||
| } | ||
|
|
||
| int score = has_upper + has_lower + has_digit + has_special; | ||
| return score >= 3; | ||
| } | ||
|
|
||
| std::string UserManager::generate_random_password(size_t length) { | ||
| const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
| char* buffer = new char[length]; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
line 383 使用 new char[length] 分配内存,line 389 用 buffer 构造 string 后直接返回,但从未调用 delete[] buffer 释放内存。每次调用 generate_random_password 都会泄漏 length 字节的堆内存。 📍 问题详情🟡 问题 1 | 严重程度:
|
||
|
|
||
| for (size_t i = 0; i < length; i++) { | ||
| buffer[i] = charset[rand() % (sizeof(charset) - 1)]; | ||
| } | ||
|
|
||
| std::string result(buffer); | ||
| return result; | ||
| } | ||
|
|
||
| Result UserManager::rate_limit_login(const std::string& ip_address) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
发现 2 个邻近问题(第 389–393 行) 📍 问题详情🟡 问题 1 | 严重程度:
|
||
| time_t now = time(nullptr); | ||
| auto it = lockout_expiry_.find(ip_address); | ||
| if (it != lockout_expiry_.end() && now < it->second) { | ||
| return Result::error(ErrorCode::AUTH_FAILED, "Account locked"); | ||
| } | ||
|
|
||
| int failures = login_failure_count_[ip_address]; | ||
| if (failures >= 5) { | ||
| lockout_expiry_[ip_address] = now + 300; | ||
| return Result::error(ErrorCode::AUTH_FAILED, "Too many attempts"); | ||
| } | ||
|
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
| ResultT<UserId> UserManager::batch_create_users(const std::vector<std::string>& usernames, | ||
| const std::vector<std::string>& passwords, | ||
| UserRole default_role) { | ||
| UserId last_id = 0; | ||
|
|
||
| for (size_t i = 0; i < usernames.size(); i++) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
line 414 循环边界使用 usernames.size(),但 line 416 访问 passwords[i]。如果 passwords.size() < usernames.size(),将导致越界访问。两个参数独立传入,没有长度一致性校验。 📍 问题详情🟡 问题 1 | 严重程度:
|
||
| const std::string& username = usernames[i]; | ||
| const std::string& password = passwords[i]; | ||
|
|
||
| if (!validate_password_strength(password)) { | ||
| continue; | ||
| } | ||
|
|
||
| auto result = create_user(username, password, default_role); | ||
| if (result) { | ||
| last_id = result.value()->id(); | ||
| } | ||
| } | ||
|
|
||
| return ResultT<UserId>::ok(last_id); | ||
| } | ||
|
|
||
| Result UserManager::batch_delete_users(const std::vector<UserId>& user_ids) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
line 431-438 batch_delete_users 在循环中调用 delete_user(user_ids[i]),但 delete_user 内部使用 lock_guard 修改 users_ 和 username_index_。batch_delete_users 本身无锁保护,在循环间隙其他线程可能插入操作,导致部分删除、状态不一致。此外 line 432 声明了 results 向量但未使用。 📍 问题详情🟡 问题 1 | 严重程度:
|
||
| std::vector<Result> results; | ||
|
|
||
| for (size_t i = 0; i < user_ids.size(); i++) { | ||
| delete_user(user_ids[i]); | ||
| } | ||
|
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
| Result UserManager::batch_update_role(const std::vector<UserId>& user_ids, UserRole new_role) { | ||
| std::shared_lock<std::shared_mutex> lock(mutex_); | ||
|
|
||
| for (UserId id : user_ids) { | ||
| auto it = users_.find(id); | ||
| if (it != users_.end()) { | ||
| it->second->set_role(new_role); | ||
| } | ||
| } | ||
|
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
| } // namespace auth | ||
| } // namespace oms | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #include "inventory/product.h" | ||
| #include "inventory/warehouse.h" | ||
| #include <algorithm> | ||
| #include <cstring> | ||
|
|
||
|
|
@@ -633,5 +634,94 @@ Result ProductCatalog::export_to_csv(const std::string& file_path) const { | |
| return Result::error(ErrorCode::NOT_IMPLEMENTED, "CSV export not implemented"); | ||
| } | ||
|
|
||
| ResultT<std::map<WarehouseId, int>> ProductCatalog::get_product_stock_distribution(ProductId product_id) { | ||
| auto result = get_product(product_id); | ||
| if (!result) { | ||
| return ResultT<std::map<WarehouseId, int>>::error(result.error_code(), result.error_message()); | ||
| } | ||
|
|
||
| return ResultT<std::map<WarehouseId, int>>::ok(result.value()->stock_info().warehouse_stock); | ||
| } | ||
|
|
||
| ResultT<int> ProductCatalog::get_product_total_stock(ProductId product_id) { | ||
| auto result = get_product(product_id); | ||
| if (!result) { | ||
| return ResultT<int>::error(result.error_code(), result.error_message()); | ||
| } | ||
|
|
||
| int total = result.value()->stock_info().total_available; | ||
| for (const auto& pair : result.value()->stock_info().warehouse_stock) { | ||
| total += pair.second; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
L652 将 total 初始化为 total_available(已是所有仓库库存之和),L653-655 又遍历 warehouse_stock 累加一次,导致 total 翻倍。batch_update_stock 中 total_available 与 warehouse_stock 同步更新,确认 total_available 即为 warehouse_stock 的总和。 📍 问题详情🟡 问题 1 | 严重程度:
|
||
| } | ||
|
|
||
| return ResultT<int>::ok(total); | ||
| } | ||
|
|
||
| Result ProductCatalog::batch_update_prices(const std::vector<ProductId>& ids, double percentage) { | ||
| for (size_t i = 0; i < ids.size(); i++) { | ||
| auto result = get_product(ids[i]); | ||
| if (result) { | ||
| double new_price = result.value()->price() * (1 + percentage / 100); | ||
| result.value()->set_price(new_price); | ||
| } | ||
| } | ||
| return Result::ok(); | ||
| } | ||
|
|
||
| Result ProductCatalog::batch_update_stock(const std::map<ProductId, int>& stock_changes) { | ||
| auto& whm = WarehouseManager::instance(); | ||
| auto wh_result = whm.get_default_warehouse(); | ||
| WarehouseId wh_id = 0; | ||
| if (wh_result) { | ||
| wh_id = wh_result.value()->id(); | ||
| } | ||
|
|
||
| for (const auto& pair : stock_changes) { | ||
| ProductId product_id = pair.first; | ||
| int delta = pair.second; | ||
|
|
||
| auto result = get_product(product_id); | ||
| if (!result) continue; | ||
|
|
||
| auto product = result.value(); | ||
| auto& stock_info = product->stock_info(); | ||
|
|
||
| stock_info.total_available += delta; | ||
| if (wh_id > 0) { | ||
| stock_info.warehouse_stock[wh_id] += delta; | ||
| } | ||
|
|
||
| product->update_timestamp(); | ||
| } | ||
|
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
| void ProductCatalog::update_indexes(Product* product, const std::string& old_category, const std::string& old_brand) { | ||
| if (old_category != product->category()) { | ||
| auto& vec = category_index_[old_category]; | ||
| for (size_t i = 0; i < vec.size(); i++) { | ||
| if (vec[i] == product->id()) { | ||
| vec[i] = vec.back(); | ||
| vec.pop_back(); | ||
| break; | ||
| } | ||
| } | ||
| category_index_[product->category()].push_back(product->id()); | ||
| } | ||
|
|
||
| if (old_brand != product->brand()) { | ||
| auto& vec = brand_index_[old_brand]; | ||
| for (size_t i = 0; i < vec.size(); i++) { | ||
| if (vec[i] == product->id()) { | ||
| vec[i] = vec.back(); | ||
| vec.pop_back(); | ||
| break; | ||
| } | ||
| } | ||
| brand_index_[product->brand()].push_back(product->id()); | ||
| } | ||
| } | ||
|
|
||
| } // namespace inventory | ||
| } // namespace oms | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -175,6 +175,7 @@ Result Warehouse::release_stock(ProductId product_id, int quantity) { | |
| return Result::error(ErrorCode::INVALID_PARAMETER, "Not enough reserved stock"); | ||
| } | ||
| reserved_stock_[product_id] -= quantity; | ||
| stock_[product_id] -= quantity; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 AI 代码审查发现问题 📋 问题概述
L178 在 release_stock 中扣减 stock_,但 confirm_deduction (L182-190) 调用 release_stock 后,L187 又执行 stock_[product_id] -= quantity,导致同一 quantity 被扣减两次。release_stock 的语义应为释放预留(仅减 reserved_stock_),扣减实际库存是 confirm_deduction 的职责。 📍 问题详情🟡 问题 1 | 严重程度:
|
||
| return Result::ok(); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 AI 代码审查发现问题
📋 问题概述
line 356-362 force_password_reset 调用 get_user(id) (line 357) 获取用户指针,但 get_user 内部的 shared_lock 在返回时已释放。line 361 通过 result.value()->security() 获取非 const 引用并修改 require_password_change,此时无锁保护。对比 update_user_profile (line 233) 和 update_user_role (line 244),这两个方法在 get_user 后都额外加了 lock_guard。
📍 问题详情
🟡 问题 1 | 严重程度:
MEDIUM| 行号:356💬 详细说明:
📝 问题代码:
💡 修复建议:
✅ 修复示例:
🔗 参考链接
无