Skip to content
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 #15

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
97 changes: 97 additions & 0 deletions .github/rE35T/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package main

import (
"encoding/base64"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"log"
"math/rand"
"net/http"
)

// 用户结构体
type User struct {
gorm.Model
Profile Profile // 与 Profile 一对一关联
Blogs []Blog `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联
Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联

ID uint // 用户ID
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
}
Comment on lines +21 to +22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Hash passwords before storing them

Storing passwords in plain text is a significant security risk. It's essential to hash passwords using a secure hashing algorithm (e.g., bcrypt) before saving them to the database.

You can use the golang.org/x/crypto/bcrypt package to hash and compare passwords. Here's how you can modify your code:

When registering a new user:

import "golang.org/x/crypto/bcrypt"

// Hash the password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
    return
}
user.Password = string(hashedPassword)

When checking the password during login:

// Compare the hashed password with the provided password
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
    // Password does not match
    return false
}
// Password matches

Please update the relevant functions to incorporate password hashing and comparison.

Comment on lines +13 to +22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove the duplicate ID field in the User struct

The User struct embeds gorm.Model, which already includes the ID field. Defining ID uint again leads to duplicate fields, which may cause unexpected behavior or compilation errors.

Apply this diff to remove the duplicate ID field:

 type User struct {
 	gorm.Model
 	Profile Profile // 与 Profile 一对一关联
 	Blogs   []Blog  `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联
 	Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联

-	ID       uint   // 用户ID
 	Username string `json:"username"` // 用户名
 	Password string `json:"password"` // 密码
 }
📝 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.

Suggested change
type User struct {
gorm.Model
Profile Profile // 与 Profile 一对一关联
Blogs []Blog `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联
Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联
ID uint // 用户ID
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
}
type User struct {
gorm.Model
Profile Profile // 与 Profile 一对一关联
Blogs []Blog `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联
Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
}


// 登录功能
func login(c *gin.Context) {
var user User

// 解析 JSON 请求
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息
return
}

// 确认用户是否存在并且密码是否正确
UserExists := checkUserExists(user.Username, user.Password)
if UserExists {
Comment on lines +35 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling in checkUserExists

The checkUserExists function may not correctly handle cases where the user does not exist. GORM returns gorm.ErrRecordNotFound when no records are found, which should be handled separately.

Modify the checkUserExists function to handle ErrRecordNotFound:

import (
    "errors"
    "gorm.io/gorm"
)

func checkUserExists(username string, password string) bool {
    var user User
    err := db.Where("username = ?", username).First(&user).Error // 查询用户
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            // User not found
            return false
        }
        log.Println("Error checking user existence:", err) // 打印错误
        return false
    }

    // Compare the hashed password
    err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
    if err != nil {
        // Password does not match
        return false
    }
    // Password matches
    return true
}

c.JSON(http.StatusOK, gin.H{"message": "登陆成功!"}) // 登录成功
c.SetCookie("username", base64.StdEncoding.EncodeToString([]byte(user.Username)), 3600, "/", "localhost", false, true) // 设置 Cookie
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid storing the username in plaintext cookies

Storing the username in a cookie, even if base64 encoded, can expose sensitive user information. Base64 encoding is not encryption and can be easily decoded. Consider using secure session tokens or JWTs for session management.

Implement session management using secure tokens. For example, generate a signed JWT token upon successful login:

import "github.com/dgrijalva/jwt-go"

// Create the token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
    "username": user.Username,
    "exp":      time.Now().Add(time.Hour * 1).Unix(),
})

// Sign and get the complete encoded token as a string
tokenString, err := token.SignedString([]byte("your-secret-key"))
if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
    return
}

// Set the token as a cookie
c.SetCookie("token", tokenString, 3600, "/", "localhost", false, true)

Ensure to validate the token on subsequent requests.

log.Println("Cookie set:", base64.StdEncoding.EncodeToString([]byte(user.Username)))
user.ID = uint(rand.Uint32()) // 随机生成用户ID(此处可能需要修改)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not assign random user IDs during login

Assigning a random user ID during login (user.ID = uint(rand.Uint32())) is inappropriate and can lead to data inconsistencies. The user ID should be retrieved from the database and should not be modified during login.

Apply this diff to remove the random ID assignment:

 log.Println("Cookie set:", base64.StdEncoding.EncodeToString([]byte(user.Username)))
-user.ID = uint(rand.Uint32()) // 随机生成用户ID(此处可能需要修改)
 return

Committable suggestion was skipped due to low confidence.

return
} else {
c.JSON(http.StatusOK, gin.H{"message": "用户未注册,请先注册!"}) // 用户未注册
}
}

// 注册功能
func register(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息
return
}

// 检查用户是否已注册
UserExists := checkUserExists(user.Username, user.Password)
exists := checkUsernameExists(user.Username)
if UserExists {
c.JSON(http.StatusOK, gin.H{"message": "该账户已注册,请转至登陆界面"}) // 已注册提示
return
}
if exists {
c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在
} else {
Comment on lines +55 to +64
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Simplify user existence checks during registration

In the register function, checking if a user exists with the same username and password is unnecessary for registration. You only need to check if the username already exists.

Apply this diff to simplify the checks:

 // 检查用户是否已注册
-UserExists := checkUserExists(user.Username, user.Password)
 exists := checkUsernameExists(user.Username)
-if UserExists {
-	c.JSON(http.StatusOK, gin.H{"message": "该账户已注册,请转至登陆界面"}) // 已注册提示
-	return
-}
 if exists {
 	c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在
 	return
 }
📝 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.

Suggested change
// 检查用户是否已注册
UserExists := checkUserExists(user.Username, user.Password)
exists := checkUsernameExists(user.Username)
if UserExists {
c.JSON(http.StatusOK, gin.H{"message": "该账户已注册,请转至登陆界面"}) // 已注册提示
return
}
if exists {
c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在
} else {
// 检查用户是否已注册
exists := checkUsernameExists(user.Username)
if exists {
c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在
return
} else {

// 创建用户记录
if err := db.Create(&user).Error; err != nil {
log.Println("Error creating user:", err) // 打印错误
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // 返回错误信息
return
}
c.JSON(http.StatusCreated, gin.H{"message": "成功注册!"}) // 注册成功
}
}

// 检查用户是否存在
func checkUserExists(username string, password string) bool {
var user User
result := db.Where("username = ?", username).First(&user) // 查询用户
if result.Error != nil {
log.Println("Error checking user existence:", result.Error) // 打印错误
return false
}

// 返回用户名和密码是否匹配
return user.Username == username && user.Password == password
}
Comment on lines +76 to +86
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle user not found error correctly in checkUserExists

In checkUserExists, the function should differentiate between a user not found and other errors. Currently, any error results in returning false, which might mask actual database errors.

Modify the function to handle ErrRecordNotFound:

func checkUserExists(username string, password string) bool {
    var user User
    err := db.Where("username = ?", username).First(&user).Error // 查询用户
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            // User not found
            return false
        }
        log.Println("Error checking user existence:", err) // 打印错误
        return false
    }

    // Compare the hashed password
    err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
    if err != nil {
        // Password does not match
        return false
    }
    // Password matches
    return true
}


// 检查用户名是否已存在
func checkUsernameExists(username string) bool {
var user User
result := db.Where("username = ?", username).First(&user) // 查询用户
if result.Error != nil {
log.Println("Error checking user existence:", result.Error) // 打印错误
return false
}
return user.Username == username
Comment on lines +91 to +96
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the return logic in checkUsernameExists

The function checkUsernameExists should return true if the user exists and false otherwise. Currently, if an error occurs (including user not found), it logs the error and returns false, which might not be the intended behavior.

Modify the function to handle ErrRecordNotFound correctly:

func checkUsernameExists(username string) bool {
    var user User
    err := db.Where("username = ?", username).First(&user).Error // 查询用户
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            // User not found
            return false
        }
        log.Println("Error checking user existence:", err) // 打印错误
        return false
    }
    return true
}

}
184 changes: 184 additions & 0 deletions .github/rE35T/blog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package main

import (
"encoding/base64"
"fmt"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"math/rand"
"net/http"
"time"
)

type Blog struct {
gorm.Model
//User
UserId uint
//一对多reply
Replies []Reply `gorm:"foreignKey:BlogID"`

ID uint
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove redundant ID field in Blog struct

The Blog struct already embeds gorm.Model, which includes an ID field. Adding another ID field can lead to confusion and potential errors.

Apply this diff to remove the redundant ID field:

 type Blog struct {
   gorm.Model
   //User
   UserId uint
   //一对多reply
   Replies []Reply `gorm:"foreignKey:BlogID"`

-  ID      uint
   Time    string
   Content string `json:"content"`
   Title   string `json:"title"`
   Author  string `json:"author"`
   Type    string `json:"type"`
 }
📝 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.

Suggested change
ID uint
Time string
Content string `json:"content"`
Title string `json:"title"`
Author string `json:"author"`
Type string `json:"type"`

Time string
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using CreatedAt from gorm.Model instead of custom Time field

Since gorm.Model includes CreatedAt, you can use it instead of defining a custom Time field in the Blog struct.

Apply this diff to remove the custom Time field:

 type Blog struct {
   gorm.Model
   //User
   UserId uint
   //一对多reply
   Replies []Reply `gorm:"foreignKey:BlogID"`

-  Time    string
   Content string `json:"content"`
   Title   string `json:"title"`
   Author  string `json:"author"`
   Type    string `json:"type"`
 }

Committable suggestion was skipped due to low confidence.

Content string `json:"content"`
Title string `json:"title"`
Author string `json:"author"`
Type string `json:"type"`
}

type Reply struct {
gorm.Model
//User
UserId uint
//blog
BlogID uint `json:"BlogID"`
Body string `json:"body"`
Who string `json:"who"`
}

// 显示我的提问与回复
func mine(c *gin.Context) {
cookieValue, err := loadCookie(c)
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle error returned by DecodeString

The DecodeString function can return an error. Currently, you are ignoring this error, which could lead to unexpected behavior if decoding fails.

Update the code to handle the error:

-cookieValue, err := loadCookie(c)
-userId, _ := base64.StdEncoding.DecodeString(cookieValue)
+cookieValue, err := loadCookie(c)
+if err != nil {
+    c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
+    return
+}
+userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
+if err != nil {
+    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
+    return
+}
+userId := string(userIdBytes)

Committable suggestion was skipped due to low confidence.

if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}

//查找user下的所有blog和blog下的所有reply
var user User
// 先通过 username 查询 User
if err := db.Where("username = ?", userId).First(&user).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
// 通过预加载获取该用户的所有 Blogs 和对应的 Replies
if err := db.Preload("Blogs.Replies").First(&user, user.ID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Blogs not found"})
return
}
c.JSON(http.StatusOK, gin.H{"user": user})
return

}

// 显示其他人的问题
func others(c *gin.Context) {
var blogs []Blog
// 预加载所有 Blogs 及其对应的 Replies
if err := db.Preload("Replies").Find(&blogs).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve blogs"})
return
}
c.JSON(http.StatusOK, gin.H{"blogs": blogs})
return
}

// 创建我的新问题
func mineNews(c *gin.Context) {
cookieValue, err := loadCookie(c)
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}

var blogs Blog
blogs.ID = uint(rand.Uint32())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not manually assign ID when using GORM

GORM automatically handles the assignment of ID for new records. Manually assigning it can lead to conflicts or unexpected behavior.

Remove the manual ID assignment:

-blogs.ID = uint(rand.Uint32())

GORM will automatically assign a unique ID when you create the record.

📝 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.

Suggested change
blogs.ID = uint(rand.Uint32())

blogs.Time = time.Now().Format("2006-01-02 15:04:05")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Utilize CreatedAt instead of custom Time field

Similar to the previous suggestion, rely on gorm.Model's CreatedAt field instead of setting a custom Time field.

Remove the manual time assignment and the Time field from the Blog struct as previously suggested.

if err := c.ShouldBind(&blogs); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
Comment on lines +88 to +91
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Handle overlapping fields when binding JSON data

Using c.ShouldBind(&blogs) after setting fields may overwrite the fields you've just set. Ensure that you handle field assignment correctly.

Adjust the code to bind the JSON into a separate struct and then map the fields:

type BlogInput struct {
    Content string `json:"content"`
    Title   string `json:"title"`
    Author  string `json:"author"`
    Type    string `json:"type"`
}

var input BlogInput
if err := c.ShouldBind(&input); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

blog := Blog{
    Content: input.Content,
    Title:   input.Title,
    Author:  input.Author,
    Type:    input.Type,
    UserId:  user.ID,
}

if err := db.Create(&blog).Error; err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create blog"})
    return
}

This approach avoids unintended overwrites and makes the code clearer.


var user User
if err := db.Where("username = ?", string(userId)).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
//键赋值
blogs.UserId = user.ID

if err := db.Create(&blogs).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}

c.JSON(http.StatusOK, gin.H{"blogs": blogs})
fmt.Println("成功发布问题")
}

func reply(c *gin.Context) {
cookieValue, err := loadCookie(c)
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle error from DecodeString in reply function

As previously noted, handle the error returned by base64.StdEncoding.DecodeString.

Update the code to handle the error:

-userId, _ := base64.StdEncoding.DecodeString(cookieValue)
+userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
+if err != nil {
+    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
+    return
+}
+userId := string(userIdBytes)
📝 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.

Suggested change
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
return
}
userId := string(userIdBytes)

if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
}
Comment on lines +110 to +115
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle missing return statements after sending error responses

In the reply function, after sending an error response, you should return to prevent further execution.

Add return statements after sending error responses:

if err != nil {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
+   return
}
📝 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.

Suggested change
func reply(c *gin.Context) {
cookieValue, err := loadCookie(c)
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
}
func reply(c *gin.Context) {
cookieValue, err := loadCookie(c)
userId, _ := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}


// 检查用户是否存在
var user User
if err := db.Where("username = ?", userId).First(&user).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}

//创建回复
var reply Reply
if err := c.ShouldBind(&reply); err != nil {

c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
Comment on lines +126 to +129
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add return statement after handling binding error

After sending an error response due to binding failure, you should return to prevent further execution.

Add a return statement:

if err := c.ShouldBind(&reply); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+   return
}
📝 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.

Suggested change
if err := c.ShouldBind(&reply); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
if err := c.ShouldBind(&reply); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}


//键赋值
reply.UserId = user.ID
//上传回复
if err := db.Create(&reply).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"})
}
Comment on lines +134 to +136
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add return statement after handling database error

Similarly, after handling the error from db.Create(&reply).Error, add a return statement.

if err := db.Create(&reply).Error; err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"})
+   return
}
📝 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.

Suggested change
if err := db.Create(&reply).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"})
}
if err := db.Create(&reply).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"})
return
}

c.JSON(http.StatusOK, gin.H{"reply": reply})
}

func blogEdit(c *gin.Context) {

var blog Blog
blogID := c.Param("id") // 获取 URL 中的博客 ID

// 查找博客
if err := db.First(&blog, blogID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})
return
}

// 绑定更新数据
if err := c.ShouldBind(&blog); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
Comment on lines +152 to +155
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid overwriting critical fields during update

Using c.ShouldBind(&blog) can overwrite fields like ID, UserId, and timestamps. Use a separate struct for update input to prevent this.

Define an input struct:

type BlogUpdateInput struct {
    Title   string `json:"title"`
    Content string `json:"content"`
    Type    string `json:"type"`
}

Update the binding:

var input BlogUpdateInput
if err := c.ShouldBind(&input); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

blog.Title = input.Title
blog.Content = input.Content
blog.Type = input.Type


// 更新博客
if err := db.Save(&blog).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update blog"})
return
}

c.JSON(http.StatusOK, gin.H{"blog": blog})
}
Comment on lines +140 to +164
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Authorize users before allowing blog edits

Currently, any user can edit any blog post. Implement authorization to ensure that only the owner of the blog can edit it.

[security]

Consider adding a check to verify that the requesting user is the owner:

cookieValue, err := loadCookie(c)
if err != nil {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
    return
}
userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
    return
}
userId := string(userIdBytes)

if blog.UserId != userId {
    c.JSON(http.StatusForbidden, gin.H{"error": "You are not allowed to edit this blog"})
    return
}

This ensures that only the author can modify their blog post.


func blogDelete(c *gin.Context) {

blogID := c.Param("id") // 获取 URL 中的博客 ID
var blog Blog

// 查找博客
if err := db.First(&blog, blogID).Error; err != nil {
Comment on lines +168 to +172
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate and parse blogID correctly

blogID obtained from c.Param("id") is a string. Ensure it's correctly converted to the appropriate type for querying.

Convert blogID to an unsigned integer:

id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid blog ID"})
    return
}

if err := db.First(&blog, id).Error; err != nil {
    c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})
    return
}

Remember to import "strconv" at the top of your file.

c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})
return
}

// 删除博客
if err := db.Delete(&blog).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete blog"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Blog deleted successfully"})
}
Comment on lines +166 to +184
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Authorize users before allowing blog deletion

Similar to editing, ensure that only the owner of the blog can delete it.

[security]

Add authorization check:

// Get the user's ID from the cookie
cookieValue, err := loadCookie(c)
if err != nil {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
    return
}
userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
    return
}
userId := string(userIdBytes)

if blog.UserId != userId {
    c.JSON(http.StatusForbidden, gin.H{"error": "You are not allowed to delete this blog"})
    return
}

Ensuring proper authorization prevents unauthorized access and modification.

39 changes: 39 additions & 0 deletions .github/rE35T/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module myproject

go 1.23.1

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/bytedance/sonic v1.12.3 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.10.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.22.1 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // 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.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.10.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.5.7 // indirect
gorm.io/gorm v1.25.12 // indirect
)
Loading