diff --git a/sh4ll0t/api/admin/admin.go b/sh4ll0t/api/admin/admin.go new file mode 100644 index 0000000..6e1413f --- /dev/null +++ b/sh4ll0t/api/admin/admin.go @@ -0,0 +1,27 @@ +package admin + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func Admin(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + if session.Get("username") != "admin" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "管理员才可以访问!"}) + return + } + var questions []db.Question + if err := db.DB.Preload("Answers").Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, questions) + +} diff --git a/sh4ll0t/api/admin/check_answer.go b/sh4ll0t/api/admin/check_answer.go new file mode 100644 index 0000000..ac644de --- /dev/null +++ b/sh4ll0t/api/admin/check_answer.go @@ -0,0 +1,47 @@ +package admin + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "net/http" + "sh4ll0t/db" + "strconv" +) + +func CheckAnswer(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + if session.Get("username") != "admin" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "管理员才可以访问!"}) + return + } + + idStr := c.PostForm("id") + checkStatusStr := c.PostForm("check") + checkStatus, err := strconv.Atoi(checkStatusStr) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "无效的审核状态"}) + return + } + + var answer db.Answer + if err := db.DB.First(&answer, idStr).Error; err != nil { + if err == gorm.ErrRecordNotFound { + c.JSON(http.StatusNotFound, gin.H{"error": "ID 不存在"}) + } else { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + } + return + } + answer.CheckStatus = checkStatus + if err := db.DB.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "审核状态更新成功"}) +} diff --git a/sh4ll0t/api/admin/check_question.go b/sh4ll0t/api/admin/check_question.go new file mode 100644 index 0000000..1a8667e --- /dev/null +++ b/sh4ll0t/api/admin/check_question.go @@ -0,0 +1,47 @@ +package admin + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "net/http" + "sh4ll0t/db" + "strconv" +) + +func CheckQuestion(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + if session.Get("username") != "admin" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "管理员才可以访问!"}) + return + } + + checkStatusStr := c.PostForm("check") + checkStatus, err := strconv.Atoi(checkStatusStr) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "无效的审核状态"}) + return + } + + idStr := c.PostForm("id") + var question db.Question + if err := db.DB.First(&question, idStr).Error; err != nil { + if err == gorm.ErrRecordNotFound { + c.JSON(http.StatusNotFound, gin.H{"error": "ID 不存在"}) + } else { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + } + return + } + question.CheckStatus = checkStatus + if err := db.DB.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "审核状态更新成功"}) +} diff --git a/sh4ll0t/api/answer/answer.go b/sh4ll0t/api/answer/answer.go new file mode 100644 index 0000000..a5b3cde --- /dev/null +++ b/sh4ll0t/api/answer/answer.go @@ -0,0 +1,37 @@ +package answer + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" + "strconv" +) + +func Answer(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + respondent := session.Get("username").(string) + idStr := c.PostForm("id") + answerText := c.PostForm("answer") + questionID, err := strconv.ParseUint(idStr, 10, 32) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "无效的问题 ID"}) + return + } + + answer := db.Answer{ + QuestionID: uint(questionID), + AnswerText: answerText, + Respondent: respondent, + } + + if err := db.DB.Create(&answer).Error; err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "回答失败"}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "回答成功"}) +} diff --git a/sh4ll0t/api/answer/change_answer.go b/sh4ll0t/api/answer/change_answer.go new file mode 100644 index 0000000..fcc8d49 --- /dev/null +++ b/sh4ll0t/api/answer/change_answer.go @@ -0,0 +1,36 @@ +package answer + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func ChangeAnswer(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + id := c.PostForm("id") + newAnswerText := c.PostForm("Answer") + var answer db.Answer + if err := db.DB.First(&answer, id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if session.Get("username") != answer.Respondent { + c.JSON(http.StatusUnauthorized, gin.H{"error": "只有本作者才可以修改!"}) + return + } + + answer.AnswerText = newAnswerText + if err := db.DB.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "修改成功"}) +} diff --git a/sh4ll0t/api/answer/delete_answer.go b/sh4ll0t/api/answer/delete_answer.go new file mode 100644 index 0000000..3ee0515 --- /dev/null +++ b/sh4ll0t/api/answer/delete_answer.go @@ -0,0 +1,31 @@ +package answer + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func DeleteAnswer(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + + id := c.PostForm("id") + var answer db.Answer + if err := db.DB.First(&answer, id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if session.Get("username") != answer.Respondent { + c.JSON(http.StatusUnauthorized, gin.H{"error": "只有本作者才可以删除!"}) + return + } + + db.DB.Delete(&db.Answer{}, "id = ?", id) + db.DB.Delete(&answer) + c.JSON(http.StatusOK, gin.H{"message": "删除成功"}) +} diff --git a/sh4ll0t/api/answer/search_answer.go b/sh4ll0t/api/answer/search_answer.go new file mode 100644 index 0000000..dd1ab2e --- /dev/null +++ b/sh4ll0t/api/answer/search_answer.go @@ -0,0 +1,37 @@ +package answer + +import ( + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func SearchAnswer(c *gin.Context) { + answer := c.PostForm("answer") + var answers []db.Answer + var questions []db.Question + err := db.DB.Where("answer_text LIKE ? AND `check` = ?", "%"+answer+"%", 1).Find(&answers).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + if len(answers) == 0 { + c.JSON(http.StatusNotFound, gin.H{"message": "未查询到相关答案"}) + return + } + err = db.DB.Preload("Answers").Where("id IN ?", getQuestionIDs(answers)).Find(&questions).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, questions) +} + +func getQuestionIDs(answers []db.Answer) []uint { + var ids []uint + for _, answer := range answers { + ids = append(ids, answer.QuestionID) + } + return ids +} diff --git a/sh4ll0t/api/question/ask.go b/sh4ll0t/api/question/ask.go new file mode 100644 index 0000000..20ef88e --- /dev/null +++ b/sh4ll0t/api/question/ask.go @@ -0,0 +1,58 @@ +package question + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" + "sh4ll0t/utils" +) + +func Ask(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + + username, ok := session.Get("username").(string) + if !ok || username == "" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名不存在"}) + return + } + + questionText := c.PostForm("question") + if questionText == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "问题内容不能为空"}) + return + } + + newQuestion := db.Question{ + QuestionText: questionText, + Questioner: username, + } + + if err := db.DB.Create(&newQuestion).Error; err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + answerText, err := utils.GenerateAIAnswer(questionText) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "无法生成答案"}) + return + } + + answer := db.Answer{ + QuestionID: newQuestion.ID, + AnswerText: answerText, + Respondent: "ai", + } + + if err := db.DB.Create(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "答案保存失败"}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "提问成功"}) +} diff --git a/sh4ll0t/api/question/change_question.go b/sh4ll0t/api/question/change_question.go new file mode 100644 index 0000000..d2f92f2 --- /dev/null +++ b/sh4ll0t/api/question/change_question.go @@ -0,0 +1,38 @@ +package question + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func ChangeQuestion(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + + id := c.PostForm("id") + questionText := c.PostForm("question") + + var existingQuestion db.Question + if err := db.DB.First(&existingQuestion, "id = ?", id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if session.Get("username") != existingQuestion.Questioner { + c.JSON(http.StatusUnauthorized, gin.H{"error": "只有本作者才可以修改!"}) + return + } + + existingQuestion.QuestionText = questionText + if err := db.DB.Save(&existingQuestion).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "修改成功"}) +} diff --git a/sh4ll0t/api/question/delete_question.go b/sh4ll0t/api/question/delete_question.go new file mode 100644 index 0000000..54ea389 --- /dev/null +++ b/sh4ll0t/api/question/delete_question.go @@ -0,0 +1,37 @@ +package question + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func DeleteQuestion(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + id := c.PostForm("id") + var username string + if err := db.DB.Model(&db.Question{}).Select("questioner").Where("id = ?", id).Scan(&username).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if session.Get("username") != username { + c.JSON(http.StatusUnauthorized, gin.H{"error": "只有本作者才可以删除!"}) + return + } + if err := db.DB.Delete(&db.Answer{}, "question_id = ?", id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if err := db.DB.Delete(&db.Question{}, id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "删除成功"}) +} diff --git a/sh4ll0t/api/question/search_question.go b/sh4ll0t/api/question/search_question.go new file mode 100644 index 0000000..1a082c0 --- /dev/null +++ b/sh4ll0t/api/question/search_question.go @@ -0,0 +1,37 @@ +package question + +import ( + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func SearchQuestion(c *gin.Context) { + question := c.PostForm("question") + var Question []db.Question + var questions []db.Question + err := db.DB.Where("question_text LIKE ? AND `check` = ?", "%"+question+"%", 1).Find(&Question).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + if len(Question) == 0 { + c.JSON(http.StatusNotFound, gin.H{"message": "未查询到相关问题"}) + return + } + err = db.DB.Preload("Answers", "`check` = ?", 1).Where("id IN ?", getIDs(Question)).Find(&questions).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, questions) +} + +func getIDs(questions []db.Question) []uint { + var ids []uint + for _, question := range questions { + ids = append(ids, question.ID) + } + return ids +} diff --git a/sh4ll0t/api/user/like.go b/sh4ll0t/api/user/like.go new file mode 100644 index 0000000..d6eaa05 --- /dev/null +++ b/sh4ll0t/api/user/like.go @@ -0,0 +1,49 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func Like(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + + id := c.PostForm("id") + var answer db.Answer + if err := db.DB.First(&answer, id).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + answer.LikesCount++ + if err := db.DB.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + var totalLikes int64 + if err := db.DB.Model(&db.Answer{}).Where("question_id = ?", answer.QuestionID).Select("SUM(likes_count)").Scan(&totalLikes).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + var question db.Question + if err := db.DB.First(&question, answer.QuestionID).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + question.TotalLikes = int(totalLikes) + if err := db.DB.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"likes_count": answer.LikesCount}) +} diff --git a/sh4ll0t/api/user/login.go b/sh4ll0t/api/user/login.go new file mode 100644 index 0000000..1d10b86 --- /dev/null +++ b/sh4ll0t/api/user/login.go @@ -0,0 +1,35 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" + "net/http" + "sh4ll0t/db" +) + +func Login(c *gin.Context) { + username := c.PostForm("username") + password := c.PostForm("password") + + var user db.User + if err := db.DB.Where("username = ?", username).First(&user).Error; err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) + return + } + + if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) + return + } + session := sessions.Default(c) + session.Set("username", username) + session.Set("authenticated", true) + + if err := session.Save(); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "登录失败"}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "登录成功"}) +} diff --git a/sh4ll0t/api/user/logout.go b/sh4ll0t/api/user/logout.go new file mode 100644 index 0000000..2ea4459 --- /dev/null +++ b/sh4ll0t/api/user/logout.go @@ -0,0 +1,20 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" +) + +func Logout(c *gin.Context) { + session := sessions.Default(c) + session.Clear() + err := session.Save() + if err != nil { + c.JSON(http.StatusOK, gin.H{"message": "登出失败"}) + return + } + //session.Options.MaxAge = -1 + //session.Save(c.Request, c.Writer) + c.JSON(http.StatusOK, gin.H{"message": "登出成功"}) +} diff --git a/sh4ll0t/api/user/register.go b/sh4ll0t/api/user/register.go new file mode 100644 index 0000000..6736df7 --- /dev/null +++ b/sh4ll0t/api/user/register.go @@ -0,0 +1,31 @@ +package user + +import ( + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" + "net/http" + "sh4ll0t/db" +) + +func Register(c *gin.Context) { + var user db.User + user.Username = c.PostForm("username") + password := c.PostForm("password") + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "密码处理失败"}) + return + } + user.Password = string(hashedPassword) + if db.DB.Where("username = ?", user.Username).First(&db.User{}).Error == nil { + c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"}) + return + } + result := db.DB.Create(&user) + if result.Error != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "注册失败"}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "注册成功"}) +} diff --git a/sh4ll0t/api/user/search_user.go b/sh4ll0t/api/user/search_user.go new file mode 100644 index 0000000..c954651 --- /dev/null +++ b/sh4ll0t/api/user/search_user.go @@ -0,0 +1,70 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func SearchUser(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + if session.Get("username") != "admin" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "管理员才可以访问!"}) + return + } + username := c.PostForm("username") + var question []db.Question + var questions []db.Question + var answers []db.Answer + err := db.DB.Where("questioner = ? AND `check` = ?", username, 1).Find(&question).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + err = db.DB.Where("respondent = ? AND `check` = ?", username, 1).Find(&answers).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + questionIDs := getIDs(question) + answerIDs := getQuestionIDs(answers) + + err = db.DB.Preload("Answers", "`check` = ?", 1).Where("id IN ? AND `check` = ?", questionIDs, 1). + Or("id IN ? AND `check` = ?", answerIDs, 1).Find(&questions).Error + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if len(question) == 0 { + c.JSON(http.StatusNotFound, gin.H{"message": "未查询到此用户"}) + return + } + + c.JSON(http.StatusOK, questions) +} + +func getIDs(questions []db.Question) []uint { + var ids []uint + for _, question := range questions { + if question.CheckStatus == 1 { + ids = append(ids, question.ID) + } + } + return ids +} + +func getQuestionIDs(answers []db.Answer) []uint { + var ids []uint + for _, answer := range answers { + if answer.CheckStatus == 1 { + ids = append(ids, answer.QuestionID) + } + } + return ids +} diff --git a/sh4ll0t/api/user/show_question_and_answer.go b/sh4ll0t/api/user/show_question_and_answer.go new file mode 100644 index 0000000..f8cb26a --- /dev/null +++ b/sh4ll0t/api/user/show_question_and_answer.go @@ -0,0 +1,23 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "net/http" + "sh4ll0t/db" +) + +func ShowQuestionAndAnswer(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + var questions []db.Question + if err := db.DB.Preload("Answers", "`check` = ?", 1).Where("`check` = ?", 1).Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, questions) +} diff --git a/sh4ll0t/api/user/sort_by_like.go b/sh4ll0t/api/user/sort_by_like.go new file mode 100644 index 0000000..9d2fe39 --- /dev/null +++ b/sh4ll0t/api/user/sort_by_like.go @@ -0,0 +1,27 @@ +package user + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "net/http" + "sh4ll0t/db" +) + +func Like_sort(c *gin.Context) { + session := sessions.Default(c) + if auth, ok := session.Get("authenticated").(bool); !ok || !auth { + c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) + return + } + + var questions []db.Question + if err := db.DB.Preload("Answers", func(db *gorm.DB) *gorm.DB { + return db.Where("`check` = 1").Order("likes_count DESC") + }).Where("`check` = 1").Order("total_likes DESC").Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, questions) +} diff --git a/sh4ll0t/apidoc/apifox.md b/sh4ll0t/apidoc/apifox.md new file mode 100644 index 0000000..d394034 --- /dev/null +++ b/sh4ll0t/apidoc/apifox.md @@ -0,0 +1,817 @@ +--- +title: 个人项目 +language_tabs: + - shell: Shell + - http: HTTP + - javascript: JavaScript + - ruby: Ruby + - python: Python + - php: PHP + - java: Java + - go: Go +toc_footers: [] +includes: [] +search: true +code_clipboard: true +highlight_theme: darkula +headingLevel: 2 +generator: "@tarslib/widdershins v4.0.23" + +--- + +# 个人项目 + +Base URLs: + +# Authentication + +# Default + +## POST 注册 + +POST /api/user/register + +输入username ,password,并在sql数据库中查找是否有该账号 + +> Body 请求参数 + +```yaml +username: test +password: test + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» username|body|string| 否 |none| +|» password|body|string| 否 |none| + +> 返回示例 + +```json +{ + "error": "用户名已存在" +} +``` + +```json +{ + "error": "注册失败" +} +``` + +```json +{ + "message": "注册成功" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 登出 + +POST /api/user/logout + +设置会话过期,并保存 + +> 返回示例 + +```json +{ + "message": "登出成功" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 提问 + +POST /api/question + +需要登录,否则不能使用该api,需要传入question,本函数会插入问题,并记录提问者,同时会默认由ai 先产生一个回答,作为默认回答 + +> Body 请求参数 + +```yaml +question: say"1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» question|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "提问成功" +} +``` + +```json +{ + "error": "无法生成答案" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 回答 + +POST /api/answer + +需要登录,否则不能使用该api,传入想回答的问题id,并插入答案,同时记录回答者 + +> Body 请求参数 + +```yaml +id: "1" +answer: HDUHELP is a computer learning community + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |none| +|» answer|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "回答成功" +} +``` + +```json +{ + "error": "回答失败" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 点赞 + +POST /api/user/like + +需要登录,否则不能使用该api,传入要点点赞的答案id,完成点赞功能 + +> Body 请求参数 + +```yaml +id: "1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |none| + +> 返回示例 + +```json +"{\n \"message\": \"点赞成功\"\n}\n{\"likes_count\": count}" +``` + +```json +{ + "error": "err" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## GET 查看问题和回答 + +GET /api/user/show + +需要登录,通过审核的问题和回答,会加入该页面,以问题和答案的对应格式输出(可以一条问题对应多个回答) + +> Body 请求参数 + +```yaml +{} + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| + +> 返回示例 + +```json +[ + { + "id": 1, + "question_text": "what is hduhelp", + "total_likes": 1, + "answers": [ + { + "answer_id": 1, + "answer_text": "HDUhelp could refer to different things depending on the context.\n\nIn the context of Hangzhou Dianzi University (HDU), it might be some kind of assistance or support related to the university. For example, it could be an online platform, a student - run help service, or an internal system within the university designed to provide help with various aspects such as academic support (course - related questions, study resources), campus life guidance (dormitory issues, campus facilities), or administrative assistance.\n\nIt could also potentially be the name of a self - developed software or service by HDU students or faculty for the benefit of the HDU community.", + "respondent": "ai", + "likes_count": 1 + } + ], + "questioner": "111" + } +] +``` + +```json +[] +``` + +```json +{ + "error": "未登录" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## GET 管理员查看所有未审核的问题和回答 + +GET /api/admin + +只有登录并且用户名为admin 的用户才能查看,会显示所有问题和答案,不管审核还是未审核 + +> 返回示例 + +```json +[ + { + "id": 1, + "question_text": "what is hduhelp", + "total_likes": 1, + "answers": [ + { + "answer_id": 1, + "answer_text": "HDUhelp could refer to different things depending on the context.\n\nIn the context of Hangzhou Dianzi University (HDU), it might be some kind of assistance or support related to the university. For example, it could be an online platform, a student - run help service, or an internal system within the university designed to provide help with various aspects such as academic support (course - related questions, study resources), campus life guidance (dormitory issues, campus facilities), or administrative assistance.\n\nIt could also potentially be the name of a self - developed software or service by HDU students or faculty for the benefit of the HDU community.", + "respondent": "ai", + "likes_count": 1 + } + ], + "questioner": "111" + } +] +``` + +```json +{ + "error": "未登录" +} +``` + +```json +{ + "error": "管理员才可以访问!" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 审核问题 + +POST /api/admin/checkQuestion + +只有登录并且用户名为admin 的用户才能查看,输入问题id,和审核参数(同意为1) + +> Body 请求参数 + +```yaml +id: "1" +check: "1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |ID 编号| +|» check|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "审核状态更新成功" +} +``` + +```json +{ + "error": "无效的审核状态" +} +``` + +```json +{ + "error": "管理员才可以访问!" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 审核回答 + +POST /api/admin/checkAnswer + +只有登录并且用户名为admin 的用户才能查看,输入答案id,和审核参数(同意为1) + +> Body 请求参数 + +```yaml +id: "1" +check: "1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |ID 编号| +|» check|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "审核状态更新成功" +} +``` + +```json +{ + "error": "无效的审核状态" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +```json +{ + "error": "管理员才可以访问!" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## GET 按点赞数量排序 + +GET /api/user/like_sort + +需要登录,会根据题目和答案的数量由高到低来排序,同时要求审核通过 + +> 返回示例 + +```json +[ + { + "id": 1, + "question_text": "what is hduhelp", + "total_likes": 1, + "answers": [ + { + "answer_id": 1, + "answer_text": "HDUhelp could refer to different things depending on the context.\n\nIn the context of Hangzhou Dianzi University (HDU), it might be some kind of assistance or support related to the university. For example, it could be an online platform, a student - run help service, or an internal system within the university designed to provide help with various aspects such as academic support (course - related questions, study resources), campus life guidance (dormitory issues, campus facilities), or administrative assistance.\n\nIt could also potentially be the name of a self - developed software or service by HDU students or faculty for the benefit of the HDU community.", + "respondent": "ai", + "likes_count": 1 + }, + { + "answer_id": 2, + "answer_text": "HDUHELP is a computer learning community", + "respondent": "lili", + "likes_count": 0 + } + ], + "questioner": "111" + } +] +``` + +```json +{ + "error": "未登录" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 修改问题 + +POST /api/question/changeQuestion + +需要登录,只有本作者才能修改,传入问题的id,和更新后的内容 + +> Body 请求参数 + +```yaml +id: "1" +question: what is vidar_team + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |ID 编号| +|» question|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "修改成功" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +```json +{ + "error": "只有本作者才可以修改!" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 修改答案 + +POST /api/answer/changeAnswer + +需要登录,只有本作者才能修改,传入答案的id,和更新后的内容 + +> Body 请求参数 + +```yaml +id: "1" +answer: I do not know + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |ID 编号| +|» answer|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "修改成功" +} +``` + +```json +{ + "error": "err" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 删除问题 + +POST /api/question/deleteQuestion + +需要登录,只有本作者才能删除,传入问题的id + +> Body 请求参数 + +```yaml +id: "1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "删除成功" +} +``` + +```json +{ + "error": "只有本作者才可以删除!" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +## POST 删除答案 + +POST /api/answer/deleteAnswer + +需要登录,只有本作者才能删除,传入问题的id + +> Body 请求参数 + +```yaml +id: "1" + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» id|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "删除成功" +} +``` + +```json +{ + "error": "err.Error()" +} +``` + +```json +{ + "error": "只有本作者才可以删除!" +} +``` + +```json +{ + "error": "未登录" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +# 主界面 + +## GET 主界面 + +GET /127.0.0.1:8000 + +接入了index.html,可以选择登录或者注册 + +> 返回示例 + +```json +"index.html" +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +# 登录 + +## POST 登录 + +POST /api/user/login + +输入账号和密码,在sql里面插入对应的数据 + +> Body 请求参数 + +```yaml +username: test +password: testtest + +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» username|body|string| 否 |none| +|» password|body|string| 否 |none| + +> 返回示例 + +```json +{ + "message": "登录成功" +} +``` + +```json +{ + "error": "用户名或密码错误" +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline| + +### 返回数据结构 + +# 数据模型 + diff --git a/sh4ll0t/db/db.go b/sh4ll0t/db/db.go new file mode 100644 index 0000000..607ce9a --- /dev/null +++ b/sh4ll0t/db/db.go @@ -0,0 +1,70 @@ +package db + +import ( + "fmt" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "log" +) + +type Answer struct { + ID uint `gorm:"column:id;primaryKey;autoIncrement"` + AnswerText string `gorm:"column:answer_text"` + Respondent string `gorm:"column:respondent"` + LikesCount int `gorm:"column:likes_count"` + QuestionID uint `gorm:"column:question_id"` + CheckStatus int `gorm:"column:check"` +} +type User struct { + Username string `gorm:"column:username"` + Password string `gorm:"column:password"` +} +type Question struct { + ID uint `gorm:"column:id;primaryKey;autoIncrement"` + QuestionText string `gorm:"column:question_text"` + TotalLikes int `gorm:"column:total_likes"` + Questioner string `gorm:"column:questioner"` + CheckStatus int `gorm:"column:check"` + Answers []Answer `gorm:"foreignKey:question_id;references:id"` +} + +var ( + dbHost = "127.0.0.1" + dbPort = "8888" + dbUser = "root" + dbName = "users" + dbPwd = "123456" + DB *gorm.DB +) + +const ( + maxOpenConns = 10 + maxIdleConns = 5 +) + +func init() { + var err error + dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPwd, dbHost, dbPort, dbName) + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic("连接数据库失败, error=" + err.Error()) + } + + sqlDB, err := DB.DB() + if err != nil { + panic("获取原生数据库连接失败, error=" + err.Error()) + } + if err := DB.AutoMigrate(&Question{}); err != nil { + log.Fatalf("创建 Question 表失败: %v", err) + } + if err := DB.AutoMigrate(&Answer{}); err != nil { + log.Fatalf("创建 Answer 表失败: %v", err) + } + if err := DB.AutoMigrate(&User{}); err != nil { + log.Fatalf("创建 User 表失败: %v", err) + } + + fmt.Println("表格创建成功!") + sqlDB.SetMaxOpenConns(maxOpenConns) + sqlDB.SetMaxIdleConns(maxIdleConns) +} diff --git a/sh4ll0t/go.mod b/sh4ll0t/go.mod new file mode 100644 index 0000000..79f966d --- /dev/null +++ b/sh4ll0t/go.mod @@ -0,0 +1,50 @@ +module sh4ll0t + +go 1.20 + +require ( + github.com/gin-contrib/sessions v1.0.1 + github.com/gin-gonic/gin v1.10.0 + github.com/go-sql-driver/mysql v1.8.1 + github.com/volcengine/volcengine-go-sdk v1.0.159 + golang.org/x/crypto v0.28.0 + gorm.io/driver/mysql v1.5.7 + gorm.io/gorm v1.25.12 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/context v1.1.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/volcengine/volc-sdk-golang v1.0.23 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/sh4ll0t/go.sum b/sh4ll0t/go.sum new file mode 100644 index 0000000..70755e7 --- /dev/null +++ b/sh4ll0t/go.sum @@ -0,0 +1,194 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI= +github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= +github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/volcengine/volc-sdk-golang v1.0.23 h1:anOslb2Qp6ywnsbyq9jqR0ljuO63kg9PY+4OehIk5R8= +github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= +github.com/volcengine/volcengine-go-sdk v1.0.159 h1:gbyZRQpPbBwN23UeWk7DiaX3GYNge59zoC89P9RphaI= +github.com/volcengine/volcengine-go-sdk v1.0.159/go.mod h1:oht5AKDJsk0fY6tV2ViqaVlOO14KSRmXZlI8ikK60Tg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/sh4ll0t/go_build_hduhelp_text b/sh4ll0t/go_build_hduhelp_text new file mode 100755 index 0000000..0223ed0 Binary files /dev/null and b/sh4ll0t/go_build_hduhelp_text differ diff --git a/sh4ll0t/img/bg.png b/sh4ll0t/img/bg.png new file mode 100644 index 0000000..baf5673 Binary files /dev/null and b/sh4ll0t/img/bg.png differ diff --git a/sh4ll0t/img/box_bg.png b/sh4ll0t/img/box_bg.png new file mode 100644 index 0000000..6b07da6 Binary files /dev/null and b/sh4ll0t/img/box_bg.png differ diff --git a/sh4ll0t/img/preloader.gif b/sh4ll0t/img/preloader.gif new file mode 100644 index 0000000..f3afe5d Binary files /dev/null and b/sh4ll0t/img/preloader.gif differ diff --git a/sh4ll0t/img/register.jpg b/sh4ll0t/img/register.jpg new file mode 100644 index 0000000..45663ad Binary files /dev/null and b/sh4ll0t/img/register.jpg differ diff --git a/sh4ll0t/img/register.png b/sh4ll0t/img/register.png new file mode 100644 index 0000000..8f166ac Binary files /dev/null and b/sh4ll0t/img/register.png differ diff --git a/sh4ll0t/img/submit.png b/sh4ll0t/img/submit.png new file mode 100644 index 0000000..7512521 Binary files /dev/null and b/sh4ll0t/img/submit.png differ diff --git a/sh4ll0t/main.go b/sh4ll0t/main.go new file mode 100755 index 0000000..c3266cb --- /dev/null +++ b/sh4ll0t/main.go @@ -0,0 +1,10 @@ +package main + +import ( + _ "github.com/go-sql-driver/mysql" + "sh4ll0t/router" +) + +func main() { + router.Run() +} diff --git a/sh4ll0t/prepare.md b/sh4ll0t/prepare.md new file mode 100644 index 0000000..fcd3702 --- /dev/null +++ b/sh4ll0t/prepare.md @@ -0,0 +1,11 @@ +# 初步设计 +## 登录注册 +## 回答功能 + 基本的提问和回答 + 增删查改 +### 额外的 + 引入ai回答 + 点赞功能 + 评论区时间排序和点赞排序 + 管理员admin权限 + 加好友功能 \ No newline at end of file diff --git a/sh4ll0t/router/router.go b/sh4ll0t/router/router.go new file mode 100644 index 0000000..d31d2c2 --- /dev/null +++ b/sh4ll0t/router/router.go @@ -0,0 +1,61 @@ +package router + +import ( + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + "github.com/gin-gonic/gin" + "sh4ll0t/api/admin" + "sh4ll0t/api/answer" + "sh4ll0t/api/question" + "sh4ll0t/api/user" +) + +func Run() { + r := gin.Default() + store := cookie.NewStore([]byte("shallot")) + store.Options(sessions.Options{ + Secure: true, + SameSite: 4, + Path: "/", + MaxAge: 86400 * 30, + }) + r.Use(sessions.Sessions("mysession", store)) + r.LoadHTMLGlob("templates/*") + r.Static("/img", "./img") + + apiGroup := r.Group("/api") + { + userGroup := apiGroup.Group("/user") + { + userGroup.POST("/register", user.Register) + userGroup.POST("/login", user.Login) + userGroup.POST("/logout", user.Logout) + userGroup.POST("/like", user.Like) + userGroup.GET("/like_sort", user.Like_sort) + userGroup.GET("/show", user.ShowQuestionAndAnswer) + userGroup.POST("/searchUser", user.SearchUser) + } + questionGroup := apiGroup.Group("/question") + { + questionGroup.POST("/", question.Ask) + questionGroup.POST("/changeQuestion", question.ChangeQuestion) + questionGroup.POST("/deleteQuestion", question.DeleteQuestion) + questionGroup.POST("/searchQuestion", question.SearchQuestion) + } + answerGroup := apiGroup.Group("/answer") + { + answerGroup.POST("/", answer.Answer) + answerGroup.POST("/searchAnswer", answer.SearchAnswer) + answerGroup.POST("/changeAnswer", answer.ChangeAnswer) + answerGroup.POST("/deleteAnswer", answer.DeleteAnswer) + } + adminGroup := apiGroup.Group("/admin") + { + adminGroup.GET("/", admin.Admin) + adminGroup.POST("/checkAnswer", admin.CheckAnswer) + adminGroup.POST("/checkQuestion", admin.CheckQuestion) + } + + } + r.Run(":8000") +} diff --git a/sh4ll0t/templates/index.html b/sh4ll0t/templates/index.html new file mode 100644 index 0000000..ea895a4 --- /dev/null +++ b/sh4ll0t/templates/index.html @@ -0,0 +1,58 @@ + + +
+ + +