-
Notifications
You must be signed in to change notification settings - Fork 26
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
feat: finish task #6
base: main
Are you sure you want to change the base?
Conversation
WalkthroughA comprehensive API documentation has been introduced for the AAAxianyu platform, detailing functionalities related to user, question, answer, best answer management, and keyword search. Additionally, a new Go module has been created for the project at Changes
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 10
🧹 Outside diff range and nitpick comments (2)
.github/AAAxianyu/hello.txt (1)
1-12
: Implement web development best practicesWhile your code creates a functional interactive webpage, there are several areas where it could be improved to align with modern web development best practices:
- Separation of Concerns: Separate HTML, CSS, and JavaScript into different files.
- Error Handling: Add fallbacks for image loading errors.
- Coding Style: Adopt a consistent coding style (e.g., indentation, naming conventions).
- Accessibility: Ensure all interactive elements are keyboard accessible.
- Performance: Optimize image sizes and use appropriate formats.
Consider restructuring your project as follows:
project/ ├── index.html ├── styles/ │ └── main.css ├── scripts/ │ └── main.js └── images/ ├── welcome.jpg └── surprise.gif
This structure separates concerns and makes your project more maintainable and scalable.
Would you like assistance in implementing these best practices or creating a more robust structure for your project?
.github/AAAxianyu/main.go (1)
67-70
: Handle Errors Returned by FunctionsIn the
sayHello
function, errors returned byioutil.ReadFile
andfmt.Fprint
are being ignored. Ignoring errors can lead to unexpected behavior and makes debugging difficult. It's important to handle these errors appropriately to ensure the application can respond to failures gracefully.Apply this diff to handle the errors:
func sayHello(w http.ResponseWriter, r *http.Request) { - b, _ := ioutil.ReadFile("./hello.txt") - _, _ = fmt.Fprint(w, string(b)) + b, err := ioutil.ReadFile("./hello.txt") + if err != nil { + http.Error(w, "Failed to read file", http.StatusInternalServerError) + return + } + if _, err := fmt.Fprint(w, string(b)); err != nil { + http.Error(w, "Failed to write response", http.StatusInternalServerError) + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
.github/AAAxianyu/go.sum
is excluded by!**/*.sum
📒 Files selected for processing (3)
- .github/AAAxianyu/go.mod (1 hunks)
- .github/AAAxianyu/hello.txt (1 hunks)
- .github/AAAxianyu/main.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .github/AAAxianyu/go.mod
<h1 style='color:orange'>Hello!Welcome to hdu!</h1> | ||
<h2>Do you have any questions?</h2> | ||
<img id='i1' src='https://p1.ssl.qhimg.com/t01892c550190fcd062.jpg'> | ||
<h3>作者实在太懒了 所以请自己输入路由叭!!!</h3> | ||
<h4>悄咪咪告诉你 点击按钮有惊喜~~</h4> | ||
<button id='b1'>点我</button> | ||
<script> | ||
document.getElementById('b1').onclick=function(){ | ||
document.getElementById('i1').src='https://imgs.qiubiaoqing.com/qiubiaoqing/imgs/607d46d2ad735lWT.gif' | ||
} | ||
|
||
</script> |
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.
Improve HTML structure and file extension
The current file has several structural issues:
- The file extension is .txt, which is incorrect for HTML content.
- The HTML lacks proper structure (missing <!DOCTYPE>, , , and tags).
These issues can lead to rendering problems and inconsistencies across browsers.
Please make the following changes:
- Rename the file to have a .html extension.
- Add the necessary HTML structure. Here's an example of how the beginning of your file should look:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to HDU</title>
</head>
<body>
<!-- Your existing content goes here -->
</body>
</html>
<h1 style='color:orange'>Hello!Welcome to hdu!</h1> | ||
<h2>Do you have any questions?</h2> | ||
<img id='i1' src='https://p1.ssl.qhimg.com/t01892c550190fcd062.jpg'> | ||
<h3>作者实在太懒了 所以请自己输入路由叭!!!</h3> | ||
<h4>悄咪咪告诉你 点击按钮有惊喜~~</h4> |
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.
Enhance HTML content, styling, and accessibility
There are several areas for improvement in the HTML content:
- Inline styling is used, which is generally discouraged.
- Chinese text is used without proper language declaration.
- The image lacks alt text, which is important for accessibility.
Please consider the following improvements:
- Move styles to a separate CSS file or a <style> tag in the .
- Add a lang attribute to the tag (e.g.,
<html lang="zh">
). - Add an alt attribute to the image.
Here's an example of how you could improve the HTML:
<h1>Hello! Welcome to HDU!</h1>
<h2>Do you have any questions?</h2>
<img id="i1" src="https://p1.ssl.qhimg.com/t01892c550190fcd062.jpg" alt="Welcome image">
<h3>作者实在太懒了 所以请自己输入路由叭!!!</h3>
<h4>悄咪咪告诉你 点击按钮有惊喜~~</h4>
And add this to your or a separate CSS file:
<style>
h1 { color: orange; }
</style>
<button id='b1'>点我</button> | ||
<script> | ||
document.getElementById('b1').onclick=function(){ | ||
document.getElementById('i1').src='https://imgs.qiubiaoqing.com/qiubiaoqing/imgs/607d46d2ad735lWT.gif' | ||
} | ||
|
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.
🛠️ Refactor suggestion
Improve JavaScript code and event handling
The current implementation uses an inline event handler in the script tag, which is not considered best practice in modern web development.
Consider the following improvements:
- Move the JavaScript to a separate file for better organization.
- Use addEventListener instead of inline event handlers.
- Consider using const for variables that won't be reassigned.
Here's an improved version of your JavaScript:
document.addEventListener('DOMContentLoaded', () => {
const button = document.getElementById('b1');
const image = document.getElementById('i1');
button.addEventListener('click', () => {
image.src = 'https://imgs.qiubiaoqing.com/qiubiaoqing/imgs/607d46d2ad735lWT.gif';
});
});
This code should be placed in a separate .js file and linked in your HTML like this:
<script src="your-script-file.js"></script>
.github/AAAxianyu/main.go
Outdated
type User struct { | ||
gorm.Model | ||
Username string `gorm:"uniqueIndex;not null" json:"username"` | ||
Password string `gorm:"not null" json:"password"` | ||
} |
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.
Inconsistent and Redundant ID Field Declarations
In the User
, Question
, and Answer
structs, there is an inconsistency in how the ID
field is declared. The User
struct embeds gorm.Model
, which already includes an ID
field of type uint
. However, the Question
and Answer
structs both embed gorm.Model
and also declare an ID
field explicitly.
This redundancy can lead to conflicts and unexpected behavior in ORM operations. It's recommended to rely solely on gorm.Model
for the ID
field or, if a custom ID is necessary, avoid embedding gorm.Model
and define required fields explicitly.
Apply this diff to remove the redundant ID
fields:
type Question struct {
gorm.Model
- ID int `gorm:"primarykey" json:"id"`
Content string `gorm:"not null" json:"content"`
BestAnswer int `gorm:"default:null" json:"best_answer"` // 最佳答案的ID
}
type Answer struct {
gorm.Model
- ID int `gorm:"primarykey" json:"id"`
Content string `gorm:"not null" json:"content"`
QuestionID int `gorm:"not null" json:"question_id"`
Votes int `gorm:"default:0" json:"votes"` // 被选择的次数
}
Also applies to: 34-39, 42-48
Store Passwords Securely Using Hashing
Currently, passwords are stored in plaintext in the database and compared directly during login. This poses a significant security risk, as it exposes user passwords to anyone who can access the database. If the database is compromised, user accounts on other platforms could also be at risk if users reuse passwords.
It's recommended to hash passwords using a secure hashing algorithm like bcrypt before storing them. During login, compare the hashed password with the stored hash to authenticate the user.
Apply this diff to incorporate password hashing:
+import (
+ "golang.org/x/crypto/bcrypt"
+ // other imports
+)
// User struct
type User struct {
gorm.Model
Username string `gorm:"uniqueIndex;not null" json:"username"`
- Password string `gorm:"not null" json:"password"`
+ Password string `gorm:"not null"` // Exclude from JSON to avoid exposure
}
// User registration
r.POST("/register", func(c *gin.Context) {
var newUser User
if err := c.ShouldBindJSON(&newUser); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
+ // Hash the password
+ hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newUser.Password), bcrypt.DefaultCost)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
+ return
+ }
+ newUser.Password = string(hashedPassword)
result := db.Create(&newUser)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "User registered successfully!"})
})
// User login
r.POST("/login", func(c *gin.Context) {
var loginUser User
if err := c.ShouldBindJSON(&loginUser); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user User
- result := db.Where("username = ? AND password = ?", loginUser.Username, loginUser.Password).First(&user)
+ result := db.Where("username = ?", loginUser.Username).First(&user)
if result.Error != nil || result.RowsAffected == 0 {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
return
}
+ // Compare the hashed password
+ if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginUser.Password)); err != nil {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
+ return
+ }
c.JSON(http.StatusOK, gin.H{"message": "Login successful!"})
})
Also applies to: 98-110, 113-126
.github/AAAxianyu/main.go
Outdated
func main() { | ||
db, err := initDB() | ||
if err != nil { | ||
panic("Failed to connect database") | ||
} | ||
http.HandleFunc("/hello", sayHello) | ||
err = http.ListenAndServe(":8080", nil) | ||
if err != nil { | ||
fmt.Println("http serve failed,err:%v\n", err) | ||
return | ||
} | ||
defer func() { | ||
sqlDB, err := db.DB() | ||
if err != nil { | ||
log.Println("Failed to get SQL DB handle:", err) | ||
} | ||
if err := sqlDB.Close(); err != nil { | ||
log.Println("Failed to close database connection:", err) | ||
} | ||
}() | ||
|
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.
Conflict in Starting Multiple HTTP Servers on the Same Port
The application attempts to start an HTTP server using the standard library with http.ListenAndServe(":8080", nil)
(line 78~) and later starts a Gin server with r.Run(":8080")
(line 326~), both on port 8080. This will cause a runtime error because only one server can listen on a given port at a time.
Additionally, since http.ListenAndServe
is blocking, any code after it (including the Gin server setup) will not execute until that server stops. This means your Gin routes will never be set up, and the application won't function as intended.
To resolve this, consider serving the /hello
endpoint using the Gin router instead of starting a separate HTTP server. Here's how you can modify the code:
func main() {
db, err := initDB()
if err != nil {
panic("Failed to connect database")
}
- http.HandleFunc("/hello", sayHello)
- err = http.ListenAndServe(":8080", nil)
- if err != nil {
- fmt.Println("http serve failed,err:%v\n", err)
- return
- }
defer func() {
sqlDB, err := db.DB()
if err != nil {
log.Println("Failed to get SQL DB handle:", err)
}
if err := sqlDB.Close(); err != nil {
log.Println("Failed to close database connection:", err)
}
}()
migrateDB(db)
- r := gin.Default()
+ r := gin.Default()
+
+ // Serve the /hello endpoint using Gin
+ r.GET("/hello", func(c *gin.Context) {
+ b, err := ioutil.ReadFile("./hello.txt")
+ if err != nil {
+ c.String(http.StatusInternalServerError, "Failed to read file")
+ return
+ }
+ c.String(http.StatusOK, string(b))
+ })
// ... [All other route handlers remain the same] ...
if err := r.Run(":8080"); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
This way, all routes are handled by the Gin router, and only one server is started on port 8080.
Also applies to: 95-329
func initDB() (*gorm.DB, error) { | ||
dsn := "root:LTY060224@tcp(127.0.0.1:23306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" | ||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return db, nil | ||
} |
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.
Avoid Hardcoding Sensitive Information in Source Code
Hardcoding database credentials, such as usernames, passwords, and connection details, directly into the source code is a significant security risk. It exposes sensitive information and can lead to security breaches if the codebase is compromised. It's recommended to store such credentials securely, for example, using environment variables or a configuration file that is not committed to version control.
Apply this diff to securely manage your database credentials:
+import (
+ "os"
+ // other imports
+)
func initDB() (*gorm.DB, error) {
- dsn := "root:LTY060224@tcp(127.0.0.1:23306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
+ dsn := os.Getenv("DATABASE_DSN")
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
return db, nil
}
Make sure to set the DATABASE_DSN
environment variable in your deployment environment with the appropriate database connection string.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func initDB() (*gorm.DB, error) { | |
dsn := "root:LTY060224@tcp(127.0.0.1:23306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" | |
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | |
if err != nil { | |
return nil, err | |
} | |
return db, nil | |
} | |
import ( | |
"os" | |
// other imports | |
) | |
func initDB() (*gorm.DB, error) { | |
dsn := os.Getenv("DATABASE_DSN") | |
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | |
if err != nil { | |
return nil, err | |
} | |
return db, nil | |
} |
.github/AAAxianyu/main.go
Outdated
func filterContent(content string) string { | ||
// 定义需要过滤的违规词列表 | ||
forbiddenWords := []string{"垃圾", "最"} | ||
|
||
// 使用正则表达式替换违规词 | ||
for _, word := range forbiddenWords { | ||
re := regexp.MustCompile(`\b` + regexp.QuoteMeta(word) + `\b`) | ||
content = re.ReplaceAllString(content, "") | ||
} | ||
return strings.TrimSpace(content) // 去除首尾空白 | ||
} |
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.
Regex Word Boundaries May Not Work with Chinese Characters
The filterContent
function uses \b
(word boundary) in the regular expression to match forbidden words. However, \b
is designed for ASCII word boundaries and may not work correctly with Chinese characters, as Chinese text doesn't use spaces to separate words.
This may cause the forbidden words not to be matched and filtered as intended. Consider removing \b
from the pattern or using Unicode-aware regular expressions to accurately match and replace forbidden Chinese words.
Apply this diff to adjust the regex pattern:
func filterContent(content string) string {
// Define the list of forbidden words
forbiddenWords := []string{"垃圾", "最"}
// Use regular expressions to replace forbidden words
for _, word := range forbiddenWords {
- re := regexp.MustCompile(`\b` + regexp.QuoteMeta(word) + `\b`)
+ re := regexp.MustCompile(regexp.QuoteMeta(word))
content = re.ReplaceAllString(content, "")
}
return strings.TrimSpace(content) // Remove leading and trailing whitespace
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func filterContent(content string) string { | |
// 定义需要过滤的违规词列表 | |
forbiddenWords := []string{"垃圾", "最"} | |
// 使用正则表达式替换违规词 | |
for _, word := range forbiddenWords { | |
re := regexp.MustCompile(`\b` + regexp.QuoteMeta(word) + `\b`) | |
content = re.ReplaceAllString(content, "") | |
} | |
return strings.TrimSpace(content) // 去除首尾空白 | |
} | |
func filterContent(content string) string { | |
// 定义需要过滤的违规词列表 | |
forbiddenWords := []string{"垃圾", "最"} | |
// 使用正则表达式替换违规词 | |
for _, word := range forbiddenWords { | |
re := regexp.MustCompile(regexp.QuoteMeta(word)) | |
content = re.ReplaceAllString(content, "") | |
} | |
return strings.TrimSpace(content) // 去除首尾空白 | |
} |
r.POST("/api/question/:id/answer", func(c *gin.Context) { | ||
id := c.Param("id") | ||
var newAnswer Answer | ||
if err := c.ShouldBindJSON(&newAnswer); err != nil { | ||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | ||
return | ||
} | ||
newAnswer.Content = filterContent(newAnswer.Content) // 过滤内容 | ||
newAnswer.QuestionID, _ = strconv.Atoi(id) | ||
result := db.Create(&newAnswer) | ||
if result.Error != nil { | ||
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()}) | ||
return | ||
} | ||
c.JSON(http.StatusOK, newAnswer) | ||
}) |
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.
Handle Error from strconv.Atoi
In the route handler for creating an answer, the error returned by strconv.Atoi(id)
is being ignored. Ignoring errors can lead to incorrect data being processed and potential runtime issues if id
is not a valid integer.
Update the code to handle the error appropriately:
newAnswer.Content = filterContent(newAnswer.Content) // Filter content
- newAnswer.QuestionID, _ = strconv.Atoi(id)
+ questionID, err := strconv.Atoi(id)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid question ID"})
+ return
+ }
+ newAnswer.QuestionID = questionID
result := db.Create(&newAnswer)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
c.JSON(http.StatusOK, newAnswer)
This ensures that if the id
parameter is not a valid integer, the client is informed, and the server doesn't attempt to process an invalid ID.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
r.POST("/api/question/:id/answer", func(c *gin.Context) { | |
id := c.Param("id") | |
var newAnswer Answer | |
if err := c.ShouldBindJSON(&newAnswer); err != nil { | |
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | |
return | |
} | |
newAnswer.Content = filterContent(newAnswer.Content) // 过滤内容 | |
newAnswer.QuestionID, _ = strconv.Atoi(id) | |
result := db.Create(&newAnswer) | |
if result.Error != nil { | |
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()}) | |
return | |
} | |
c.JSON(http.StatusOK, newAnswer) | |
}) | |
r.POST("/api/question/:id/answer", func(c *gin.Context) { | |
id := c.Param("id") | |
var newAnswer Answer | |
if err := c.ShouldBindJSON(&newAnswer); err != nil { | |
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | |
return | |
} | |
newAnswer.Content = filterContent(newAnswer.Content) // Filter content | |
questionID, err := strconv.Atoi(id) | |
if err != nil { | |
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid question ID"}) | |
return | |
} | |
newAnswer.QuestionID = questionID | |
result := db.Create(&newAnswer) | |
if result.Error != nil { | |
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()}) | |
return | |
} | |
c.JSON(http.StatusOK, newAnswer) | |
}) |
r.PUT("/api/question/:id/best-answer", func(c *gin.Context) { | ||
id := c.Param("id") | ||
bestAnswerID := c.PostForm("best_answer_id") | ||
if bestAnswerID == "" { | ||
c.JSON(http.StatusBadRequest, gin.H{"error": "Missing best_answer_id parameter"}) | ||
return | ||
} | ||
|
||
var question Question | ||
result := db.Where("id = ?", id).First(&question) | ||
if result.Error != nil || result.RowsAffected == 0 { | ||
c.JSON(http.StatusNotFound, gin.H{"error": "Question not found"}) | ||
return | ||
} | ||
|
||
// 更新问题的最佳答案 | ||
db.Model(&question).Update("best_answer", bestAnswerID) | ||
|
||
// 更新答案的投票计数 | ||
db.Model(&Answer{}).Where("id = ?", bestAnswerID).Update("votes", gorm.Expr("votes + 1")) | ||
|
||
c.JSON(http.StatusOK, gin.H{"message": "Best answer selected successfully!"}) | ||
}) |
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.
Use Appropriate Data Binding for PUT Request
In the route handler for selecting the best answer (lines 267-289~), the code attempts to retrieve best_answer_id
using c.PostForm("best_answer_id")
in a PUT request. However, c.PostForm
is designed to work with POST requests and form data. In a PUT request, data is typically sent in the request body, and using c.PostForm
may not retrieve the data as intended.
Consider using c.ShouldBindJSON
to properly bind the request data from the JSON body. Here's how you can modify the code:
- bestAnswerID := c.PostForm("best_answer_id")
- if bestAnswerID == "" {
- c.JSON(http.StatusBadRequest, gin.H{"error": "Missing best_answer_id parameter"})
- return
- }
+ var requestBody struct {
+ BestAnswerID int `json:"best_answer_id" binding:"required"`
+ }
+ if err := c.ShouldBindJSON(&requestBody); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ bestAnswerID := requestBody.BestAnswerID
var question Question
result := db.Where("id = ?", id).First(&question)
if result.Error != nil || result.RowsAffected == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "Question not found"})
return
}
// Update the best answer for the question
- db.Model(&question).Update("best_answer", bestAnswerID)
+ db.Model(&question).Update("best_answer", bestAnswerID)
// Increment the vote count for the answer
db.Model(&Answer{}).Where("id = ?", bestAnswerID).Update("votes", gorm.Expr("votes + 1"))
c.JSON(http.StatusOK, gin.H{"message": "Best answer selected successfully!"})
Ensure that clients send the best_answer_id
in the JSON body when making the PUT request.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
r.PUT("/api/question/:id/best-answer", func(c *gin.Context) { | |
id := c.Param("id") | |
bestAnswerID := c.PostForm("best_answer_id") | |
if bestAnswerID == "" { | |
c.JSON(http.StatusBadRequest, gin.H{"error": "Missing best_answer_id parameter"}) | |
return | |
} | |
var question Question | |
result := db.Where("id = ?", id).First(&question) | |
if result.Error != nil || result.RowsAffected == 0 { | |
c.JSON(http.StatusNotFound, gin.H{"error": "Question not found"}) | |
return | |
} | |
// 更新问题的最佳答案 | |
db.Model(&question).Update("best_answer", bestAnswerID) | |
// 更新答案的投票计数 | |
db.Model(&Answer{}).Where("id = ?", bestAnswerID).Update("votes", gorm.Expr("votes + 1")) | |
c.JSON(http.StatusOK, gin.H{"message": "Best answer selected successfully!"}) | |
}) | |
r.PUT("/api/question/:id/best-answer", func(c *gin.Context) { | |
id := c.Param("id") | |
var requestBody struct { | |
BestAnswerID int `json:"best_answer_id" binding:"required"` | |
} | |
if err := c.ShouldBindJSON(&requestBody); err != nil { | |
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | |
return | |
} | |
bestAnswerID := requestBody.BestAnswerID | |
var question Question | |
result := db.Where("id = ?", id).First(&question) | |
if result.Error != nil || result.RowsAffected == 0 { | |
c.JSON(http.StatusNotFound, gin.H{"error": "Question not found"}) | |
return | |
} | |
// Update the best answer for the question | |
db.Model(&question).Update("best_answer", bestAnswerID) | |
// Increment the vote count for the answer | |
db.Model(&Answer{}).Where("id = ?", bestAnswerID).Update("votes", gorm.Expr("votes + 1")) | |
c.JSON(http.StatusOK, gin.H{"message": "Best answer selected successfully!"}) | |
}) |
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.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
.github/AAAxianyu/API 文档 (1)
329-329
: Maintain a professional tone in the summaryIn line 329, the phrase "(也许算?)" ("maybe counts?") introduces an informal tone to the documentation. Consider revising it to maintain a professional and consistent style throughout the document.
Apply this diff to adjust the wording:
- (7)一个简单的前端欢迎页面(也许算?) + (7)一个简单的前端欢迎页面
|
||
总结:这段代码实现了(1)用户的注册和登陆 | ||
(2)问题的创建,搜索,更新,删除 | ||
(3)答案的创建,搜错,更新,删除 |
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.
Correct the typo in "搜错" to "搜索"
In line 325, the term "搜错" (search error) should be corrected to "搜索" (search) to accurately describe the functionality related to answers.
Apply this diff to fix the typo:
- (3)答案的创建,搜错,更新,删除
+ (3)答案的创建,搜索,更新,删除
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
(3)答案的创建,搜错,更新,删除 | |
(3)答案的创建,搜索,更新,删除 |
"id": 1, | ||
"content": "Life's purpose is subjective.", | ||
"question_id": 1, | ||
"votes": 0} |
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.
Fix JSON formatting in the response example
In line 232, the closing brace }
is on the same line as the last property, which may cause confusion and inconsistency with other examples. It should be placed on a new line for better readability and consistent formatting.
Apply this diff to fix the formatting:
- "votes": 0}
+ "votes": 0
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"votes": 0} | |
"votes": 0 | |
} |
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.
最好分模块去写;User和问答割裂了,可以考虑联系起来,不然不知道问题和回答是谁的;考虑了违禁词过滤很不错,有没有更优的过滤策略;可以进一步分析场景的需求,完善功能
feat: finish task
Summary by CodeRabbit
New Features
Bug Fixes
Documentation