Files
memora/memora-api/internal/handler/word.go

183 lines
4.4 KiB
Go

package handler
import (
"fmt"
"net/http"
"strconv"
"strings"
"memora-api/internal/request"
"memora-api/internal/service"
"github.com/gin-gonic/gin"
)
type WordHandler struct {
wordService *service.WordService
}
func userIDFromContext(c *gin.Context) int64 {
v, ok := c.Get("user_id")
if !ok {
return 1
}
uid, ok := v.(int64)
if !ok || uid <= 0 {
return 1
}
return uid
}
func NewWordHandler(wordService *service.WordService) *WordHandler {
return &WordHandler{wordService: wordService}
}
// 添加单词(记忆模式)
func (h *WordHandler) AddWord(c *gin.Context) {
var req request.AddWordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 调用有道API查询
youdaoResp, err := h.wordService.QueryWord(req.Word)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败: " + err.Error()})
return
}
if youdaoResp.ErrorCode != "0" && youdaoResp.ErrorCode != "" {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("有道API错误: %s", youdaoResp.ErrorCode)})
return
}
// 保存到数据库
word, err := h.wordService.SaveWord(userIDFromContext(c), req.Word, youdaoResp)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "单词添加成功",
"data": word,
})
}
// 获取复习单词列表
func (h *WordHandler) GetReviewWords(c *gin.Context) {
mode := c.DefaultQuery("mode", "spelling")
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
words, err := h.wordService.GetReviewWords(userIDFromContext(c), mode, limit)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": words})
}
// 提交复习答案
func (h *WordHandler) SubmitReview(c *gin.Context) {
var req request.ReviewAnswerRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result, err := h.wordService.SubmitReviewAnswer(userIDFromContext(c), req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": result})
}
// 获取所有单词
func (h *WordHandler) GetWords(c *gin.Context) {
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
query := strings.TrimSpace(c.DefaultQuery("q", ""))
words, total, err := h.wordService.GetAllWords(limit, offset, query)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"data": words,
"total": total,
})
}
// 获取统计信息
func (h *WordHandler) GetStatistics(c *gin.Context) {
stats, err := h.wordService.GetStatistics(userIDFromContext(c))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": stats})
}
// 获取音频文件
func (h *WordHandler) GetAudio(c *gin.Context) {
word := c.Query("word")
audioType := c.DefaultQuery("type", "uk")
if word == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "缺少word参数"})
return
}
// very small sanitization
word = strings.TrimSpace(word)
if word == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "word为空"})
return
}
for _, r := range word {
if !(r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z') {
c.JSON(http.StatusBadRequest, gin.H{"error": "word包含非法字符"})
return
}
}
filename := word + "_" + audioType + ".mp3"
path := "./audio/" + filename
c.File(path)
}
func (h *WordHandler) CreateStudySession(c *gin.Context) {
var req request.CreateStudySessionRequest
_ = c.ShouldBindJSON(&req)
words, err := h.wordService.CreateStudySession(userIDFromContext(c), req.Limit)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": words})
}
func (h *WordHandler) SubmitStudyAnswer(c *gin.Context) {
var req request.SubmitStudyAnswerRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result, err := h.wordService.SubmitStudyAnswer(userIDFromContext(c), req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": result})
}