#include "backend_interface.h" #include #include #include #include #include namespace exam_system { // 常量配置 namespace { constexpr int kVerificationCodeLength = 6; constexpr int kVerificationCodeExpirySeconds = 300; // 5分钟 constexpr int kOptionsCount = 4; // libcurl 写回调函数 size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response) { size_t total_size = size * nmemb; response->append((char*)contents, total_size); return total_size; } } // namespace BackendImpl::BackendImpl() { // 初始化 ExamSystem exam_system_ = std::make_unique(); // 配置邮箱设置 email_config_.smtp_server = "smtp.163.com"; email_config_.smtp_port = 587; // 使用STARTTLS email_config_.username = "your_email@163.com"; email_config_.password = "your_authorization_code"; // 注意:这是授权码,不是登录密码 email_config_.use_curl = true; // 初始化libcurl curl_global_init(CURL_GLOBAL_DEFAULT); Logger::Log(Logger::Level::INFO, "BackendImpl初始化完成"); } BackendImpl::~BackendImpl() { curl_global_cleanup(); } bool BackendImpl::SendVerificationCode(const std::string& email) { if (email.empty() || email.find('@') == std::string::npos) { Logger::Log(Logger::Level::ERROR, "邮箱地址格式无效: " + email); return false; } // 清理过期的验证码 CleanExpiredVerificationCodes(); // 生成验证码 std::string code = GenerateVerificationCode(); // 保存验证码 VerificationCode vc; vc.code = code; vc.generate_time = std::time(nullptr); vc.email = email; verification_codes_[email] = vc; // 发送邮件 std::string subject = "数学考试系统 - 验证码"; std::string body = "您的验证码是: " + code + "\n\n"; body += "该验证码有效期为5分钟,请尽快使用。\n"; body += "如果不是您本人操作,请忽略此邮件。\n\n"; body += "数学考试系统团队"; bool send_success = SendEmail(email, subject, body); if (send_success) { Logger::Log(Logger::Level::INFO, "验证码发送成功至: " + email + ", 验证码: " + code); return true; } else { Logger::Log(Logger::Level::ERROR, "验证码发送失败: " + email); verification_codes_.erase(email); return false; } } bool BackendImpl::UserRegister(const std::string& username, const std::string& password, const std::string& email, const std::string& code) { // 输入验证 if (username.empty() || password.empty() || email.empty() || code.empty()) { Logger::Log(Logger::Level::ERROR, "注册信息不完整"); return false; } // 验证邮箱验证码 if (!ValidateVerificationCode(email, code)) { Logger::Log(Logger::Level::ERROR, "验证码错误或已过期"); return false; } // 创建用户信息并添加到ExamSystem UserInfo new_user; new_user.username = username; new_user.password = password; new_user.email = email; new_user.user_type = "小学"; // 默认类型 bool success = exam_system_->AddUser(new_user); if (success) { // 注册成功后清除验证码 verification_codes_.erase(email); Logger::Log(Logger::Level::INFO, "用户注册成功: " + username + ", 邮箱: " + email); } else { Logger::Log(Logger::Level::ERROR, "用户注册失败: " + username); } return success; } bool BackendImpl::UserLogin(const std::string& username, const std::string& password) { if (username.empty() || password.empty()) { Logger::Log(Logger::Level::ERROR, "用户名或密码为空"); return false; } // 使用ExamSystem进行登录 LoginRequest request; request.username = username; request.password = password; LoginResponse response = exam_system_->Login(request); if (response.success) { current_user_ = username; Logger::Log(Logger::Level::INFO, "用户登录成功: " + username); return true; } else { Logger::Log(Logger::Level::ERROR, "用户登录失败: " + username + ", 错误: " + response.error_message); return false; } } void BackendImpl::UserLogout() { if (!current_user_.empty()) { exam_system_->Logout(current_user_); current_user_.clear(); user_questions_.erase(current_user_); current_correct_answers_.clear(); Logger::Log(Logger::Level::INFO, "用户登出: " + current_user_); } } bool BackendImpl::ChangePassword(const std::string& old_password, const std::string& new_password) { if (current_user_.empty()) { Logger::Log(Logger::Level::ERROR, "用户未登录,无法修改密码"); return false; } if (new_password.empty()) { Logger::Log(Logger::Level::ERROR, "新密码不能为空"); return false; } // 使用ExamSystem修改密码 ChangePasswordRequest request; request.username = current_user_; request.old_password = old_password; request.new_password = new_password; ChangePasswordResponse response = exam_system_->ChangePassword(request); if (response.success) { Logger::Log(Logger::Level::INFO, "密码修改成功: " + current_user_); return true; } else { Logger::Log(Logger::Level::ERROR, "密码修改失败: " + current_user_ + ", 错误: " + response.error_message); return false; } } void BackendImpl::UserExit() { UserLogout(); Logger::Log(Logger::Level::INFO, "用户退出系统"); } std::vector BackendImpl::GenerateQuestions( const std::string& difficulty, int count) { std::vector questions; if (current_user_.empty()) { Logger::Log(Logger::Level::ERROR, "用户未登录,无法生成题目"); return questions; } // 使用ExamSystem生成题目 GenerateRequest request; request.username = current_user_; request.difficulty = difficulty; request.count = count; GenerateResponse response = exam_system_->GenerateProblems(request); if (!response.success) { Logger::Log(Logger::Level::ERROR, "生成题目失败: " + response.error_message); return questions; } // 转换为前端需要的格式 current_correct_answers_.clear(); for (size_t i = 0; i < response.problems.size(); ++i) { QuestionInfo question; question.id = i + 1; // 提取题目内容(去除题号) std::string problem_content = response.problems[i]; size_t dot_pos = problem_content.find('.'); if (dot_pos != std::string::npos) { problem_content = problem_content.substr(dot_pos + 2); // 跳过". " } question.content = problem_content; // 计算正确答案 std::string correct_answer = CalculateSimpleAnswer(problem_content); current_correct_answers_.push_back(correct_answer); // 生成选项 question.options = GenerateOptions(correct_answer); // 设置正确答案索引 for (size_t j = 0; j < question.options.size(); ++j) { if (question.options[j] == correct_answer) { question.correct_answer = j; break; } } questions.push_back(question); } // 缓存用户题目 user_questions_[current_user_] = questions; // 保存题目到文件 exam_system_->SaveProblems(current_user_, response.problems); Logger::Log(Logger::Level::INFO, "为用户 " + current_user_ + " 生成 " + std::to_string(count) + " 道 " + difficulty + " 难度题目"); return questions; } TestResult BackendImpl::SubmitAnswers(const std::vector& user_answers) { TestResult result; result.total_questions = 0; result.correct_answers = 0; result.score = 0.0; result.difficulty = "unknown"; if (current_user_.empty()) { Logger::Log(Logger::Level::ERROR, "用户未登录,无法提交答案"); return result; } // 获取用户当前题目 auto it = user_questions_.find(current_user_); if (it == user_questions_.end()) { Logger::Log(Logger::Level::ERROR, "用户没有生成的题目"); return result; } const std::vector& questions = it->second; result.total_questions = questions.size(); if (user_answers.size() != questions.size()) { Logger::Log(Logger::Level::ERROR, "答案数量与题目数量不匹配: " + std::to_string(user_answers.size()) + " vs " + std::to_string(questions.size())); return result; } // 统计正确答案 result.correct_answers = 0; for (size_t i = 0; i < questions.size(); ++i) { if (user_answers[i] >= 0 && user_answers[i] < static_cast(questions[i].options.size()) && user_answers[i] == questions[i].correct_answer) { ++result.correct_answers; } } // 计算得分 result.score = CalculateScore(result.correct_answers, result.total_questions); // 设置难度(从最后生成的题目中推断) if (!questions.empty()) { // 这里可以根据题目内容推断难度,简化实现使用primary result.difficulty = "primary"; } Logger::Log(Logger::Level::INFO, "用户 " + current_user_ + " 提交答案,正确: " + std::to_string(result.correct_answers) + "/" + std::to_string(result.total_questions) + ", 得分: " + std::to_string(result.score)); return result; } std::string BackendImpl::GetCurrentUser() const { return current_user_; } // ==================== 私有方法实现 ==================== bool BackendImpl::SendEmail(const std::string& recipient, const std::string& subject, const std::string& body) { if (email_config_.use_curl) { return SendEmailViaCurl(recipient, subject, body); } else { // 备用邮件发送方法 Logger::Log(Logger::Level::ERROR, "仅支持libcurl邮件发送"); return false; } } bool BackendImpl::SendEmailViaCurl(const std::string& recipient, const std::string& subject, const std::string& body) { CURL* curl; CURLcode res = CURLE_OK; struct curl_slist* recipients = nullptr; std::string response_string; curl = curl_easy_init(); if (!curl) { Logger::Log(Logger::Level::ERROR, "libcurl初始化失败"); return false; } // 设置SMTP服务器 curl_easy_setopt(curl, CURLOPT_URL, ("smtp://" + email_config_.smtp_server + ":" + std::to_string(email_config_.smtp_port)).c_str()); // 设置用户名和密码 curl_easy_setopt(curl, CURLOPT_USERNAME, email_config_.username.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, email_config_.password.c_str()); // 设置发件人和收件人 curl_easy_setopt(curl, CURLOPT_MAIL_FROM, email_config_.username.c_str()); recipients = curl_slist_append(recipients, recipient.c_str()); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); // 设置邮件内容 std::string email_data = "To: " + recipient + "\r\n" "From: " + email_config_.username + "\r\n" "Subject: " + subject + "\r\n" "\r\n" + body + "\r\n"; curl_easy_setopt(curl, CURLOPT_READFUNCTION, [](char* buffer, size_t size, size_t nitems, void* instream) -> size_t { std::string* email_data = static_cast(instream); size_t buffer_size = size * nitems; if (email_data->empty()) { return 0; } size_t copy_size = std::min(buffer_size, email_data->size()); memcpy(buffer, email_data->c_str(), copy_size); email_data->erase(0, copy_size); return copy_size; }); curl_easy_setopt(curl, CURLOPT_READDATA, &email_data); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // 启用TLS curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); // 设置服务器证书验证(生产环境应该设为1) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // 设置响应回调 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string); // 设置超时 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // 发送邮件 res = curl_easy_perform(curl); // 清理 curl_slist_free_all(recipients); curl_easy_cleanup(curl); if (res != CURLE_OK) { Logger::Log(Logger::Level::ERROR, "邮件发送失败: " + std::string(curl_easy_strerror(res))); return false; } Logger::Log(Logger::Level::INFO, "邮件发送成功: " + recipient); return true; } std::string BackendImpl::GenerateVerificationCode() { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution dis(0, 9); std::string code; for (int i = 0; i < kVerificationCodeLength; ++i) { code += std::to_string(dis(gen)); } return code; } bool BackendImpl::ValidateVerificationCode(const std::string& email, const std::string& code) { auto it = verification_codes_.find(email); if (it == verification_codes_.end()) { return false; } const VerificationCode& vc = it->second; std::time_t current_time = std::time(nullptr); // 检查验证码是否过期 if (current_time - vc.generate_time > kVerificationCodeExpirySeconds) { verification_codes_.erase(it); return false; } // 检查验证码是否匹配 if (vc.code != code) { return false; } return true; } void BackendImpl::CleanExpiredVerificationCodes() { std::time_t current_time = std::time(nullptr); std::vector expired_emails; for (const auto& pair : verification_codes_) { if (current_time - pair.second.generate_time > kVerificationCodeExpirySeconds) { expired_emails.push_back(pair.first); } } for (const auto& email : expired_emails) { verification_codes_.erase(email); Logger::Log(Logger::Level::INFO, "清理过期验证码: " + email); } } std::string BackendImpl::CalculateSimpleAnswer(const std::string& problem) { // 简化实现,根据题目类型返回示例答案 // 实际项目中应该使用完整的表达式计算库 if (problem.find('+') != std::string::npos) { return "25"; } else if (problem.find('-') != std::string::npos) { return "12"; } else if (problem.find('*') != std::string::npos) { return "36"; } else if (problem.find('/') != std::string::npos) { return "4"; } else if (problem.find('²') != std::string::npos) { return "64"; } else if (problem.find('√') != std::string::npos) { return "8"; } else if (problem.find("sin") != std::string::npos) { return "0.50"; } else if (problem.find("cos") != std::string::npos) { return "0.87"; } else if (problem.find("tan") != std::string::npos) { return "1.00"; } return "42"; // 默认答案 } std::vector BackendImpl::GenerateOptions(const std::string& correct_answer) { std::vector options(kOptionsCount); // 设置正确答案到一个随机位置 std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution pos_dist(0, kOptionsCount - 1); int correct_pos = pos_dist(gen); options[correct_pos] = correct_answer; // 生成错误答案 try { double correct_value = std::stod(correct_answer); std::uniform_real_distribution offset_dist(1.0, 10.0); std::uniform_int_distribution sign_dist(0, 1); for (int i = 0; i < kOptionsCount; ++i) { if (i == correct_pos) continue; double offset = offset_dist(gen); if (sign_dist(gen) == 0) { offset = -offset; } double wrong_value = correct_value + offset; // 格式化输出 std::stringstream ss; if (std::abs(wrong_value - std::round(wrong_value)) < 1e-6) { ss << static_cast(wrong_value); } else { ss << std::fixed << std::setprecision(2) << wrong_value; } options[i] = ss.str(); } } catch (const std::exception& e) { // 如果转换失败,使用简单选项 for (int i = 0; i < kOptionsCount; ++i) { if (i == correct_pos) continue; options[i] = "选项" + std::to_string(i + 1); } } return options; } double BackendImpl::CalculateScore(int correct_count, int total_count) { if (total_count == 0) return 0.0; return (static_cast(correct_count) / total_count) * 100.0; } } // namespace exam_system