-
Notifications
You must be signed in to change notification settings - Fork 1
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 add follow, counts-and-status- related functions #2
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis update revises file exclusions in .gitignore, refactors controller methods to streamline API endpoints (for likes, follows, comments, tokens, and user profile updates), and modernizes DAO and service layers by replacing concrete types with interfaces. In addition, new API endpoints and documentation updates have been introduced, data models have been extended or adjusted, and several files now support dependency injection via Wire. Other changes include improvements to JWT token management and overall initialization processes. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as C
participant Router as R
participant PostCtrl as PC
participant PostSvc as PS
participant Config as CF
C->>R: GET /api/getToken
R->>PC: Handle GetToken request
PC->>PS: Invoke GetToken()
PS->>CF: Read configuration file
CF-->>PS: Return configuration data
PS->>PS: Generate upload token
PS-->>PC: Return token
PC-->>R: Send token response
R-->>C: Deliver token
sequenceDiagram
participant Client as C
participant Router as R
participant UserCtrl as UC
participant TokenSvc as TS
C->>R: POST /api/logout (with token)
R->>UC: Process Logout request
UC->>TS: Call InvalidateToken(token)
TS-->>UC: Return invalidated token/info
UC-->>R: Send logout response
R-->>C: Confirm logout success
Poem
✨ Finishing Touches
🪧 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: 20
🔭 Outside diff range comments (2)
models/post.go (1)
14-14
: Fix typo in GORM tag.There's a typo in the GORM tag for ImageURL field (
grom
instead ofgorm
).- ImageURL string `grom:"type:varchar(255)" json:"urls"` + ImageURL string `gorm:"type:varchar(255)" json:"urls"`services/email.go (1)
72-91
: Enhance email security and configuration.The email configuration should be more secure and configurable.
func (es *EmailService) SendEmail(email, code string) error { + sender := os.Getenv("EMAIL_SENDER") + if sender == "" { + return fmt.Errorf("email sender not configured") + } message := gomail.NewMessage() - message.SetHeader("From", "[email protected]") + message.SetHeader("From", sender) message.SetHeader("To", email) - message.SetHeader("Subject", "小知账号注册") + message.SetHeader("Subject", os.Getenv("EMAIL_SUBJECT")) password := os.Getenv("EMAIL_PASSWORD") if password == "" { return fmt.Errorf("未设置邮件授权码,请检查环境变量") } - message.SetBody("text/plain", "【小知创想家】您的验证码"+code+"该验证码5分钟内有效,请勿泄露于他人!") - dialer := gomail.NewDialer("smtp.qq.com", 587, "[email protected]", password) + template := os.Getenv("EMAIL_TEMPLATE") + message.SetBody("text/plain", fmt.Sprintf(template, code)) + dialer := gomail.NewDialer( + os.Getenv("SMTP_HOST"), + 587, + sender, + password, + )
🧹 Nitpick comments (26)
services/post.go (2)
180-185
: Error handling improvement suggestion.
Currently, errors are only printed. Consider returning or logging them more thoroughly higher up to ensure issues aren't silently swallowed.
201-215
: Token generation correctness.
Generates an upload token for Qiniu Cloud storage. Error handling is correct, but the nil return on line 213 might be a small oversight; could return the error for consistency.dao/likes.go (2)
217-225
: SearchCommentByID for commenter info.
The triple return (commenterID, body, error) is consistent, though consider returning a struct for clarity.
227-235
: SearchReplyByID for replyer info.
Same pattern as SearchCommentByID. Returning a struct could improve maintainability.services/like.go (5)
32-32
: Debug print statement.
Using fmt.Print for debugging is okay short-term. Consider structured logging if you need more permanent logs.
415-419
: GetUserFolower method name.
Small naming nit: consider “GetUserFollower” for consistency. Currently it fetches the followees, so be sure it's intended.
460-476
: GetUserFoloweeList logic.
Retrieves the followees by ID, then fetches user data. Consider concurrency or batch fetching to optimize performance at scale.
478-494
: GetUserFolowerList logic.
Same pattern as GetUserFoloweeList. Also good to confirm naming consistency: “Folower” vs “Follower.”
568-573
: Bulk user iteration for data sync.
Calls multiple sync methods for each user. Consider chunking or concurrency if the user set is large.controllers/post.go (2)
495-508
: Consistent logic for retrieving and updating comment messages
Consider logging errors from the goroutine if any occur.
522-532
: Ensure concurrency error handling
When spawning a goroutine for UpdateMessageStatus, consider capturing or logging any returned errors.controllers/like.go (5)
95-102
: Check combined error approach
Using a single fallback mask for different errors might hamper debugging.
335-336
: Potential naming mismatch
Using "Postid" in c.Param might be inconsistent with "PostID" usage.- PostID := c.Param("Postid") + PostID := c.Param("postid")
522-533
: Ensure error context
If GetUserFoloweeList fails, it returns only a generic error. Logging the details could help.
572-579
: Check for retrieval errors
Methods like GetPostLikeStatus could fail silently. Consider improved error reporting.
633-642
: GetFollowStatus
Optionally verify the existence of both users.services/wire.go (1)
5-10
: Consider consistent formatting with other wire.go files.For consistency with other wire.go files in the codebase, consider moving the closing parenthesis to a new line.
var ProviderSet = wire.NewSet( NewEmailService, NewLikeService, NewPostService, NewTokenService, - NewUserService) + NewUserService, +)main.go (1)
16-23
: Consider improving error handling and message consistency.
- The error message should be in English for consistency.
- Consider adding validation for malformed DSN strings.
func ProvideDBConnectionString() string { dsn := os.Getenv("DSN") if dsn == "" { - panic("未设置数据库连接,请检查环境变量") + panic("Database connection string not set. Please check environment variables") } + // Validate DSN format + if !strings.Contains(dsn, "@") || !strings.Contains(dsn, "/") { + panic("Invalid DSN format. Expected format: [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]") + } return dsn }models/user.go (1)
13-17
: Consider improving configuration management and field validation.
- Default image URLs should be moved to configuration.
- Consider adding validation for count fields.
+const ( + DefaultImageURL = "https://mini-project.muxixyz.com/lmAp5ighezmJ-vJ7SMnSmCW9Mfau" +) type User struct { // ... - LikeCount int `gorm:"default:0"` - FollowerCount int `gorm:"default:0"` - FolloweeCount int `gorm:"default:0"` + LikeCount int `gorm:"default:0;check:like_count >= 0"` + FollowerCount int `gorm:"default:0;check:follower_count >= 0"` + FolloweeCount int `gorm:"default:0;check:followee_count >= 0"` - ImageURL string `gorm:"default:'https://mini-project.muxixyz.com/lmAp5ighezmJ-vJ7SMnSmCW9Mfau'" json:"url"` - PageBackgroundURL string `gorm:"default:'https://mini-project.muxixyz.com/lmAp5ighezmJ-vJ7SMnSmCW9Mfau'" json:"backgroundURL"` + ImageURL string `gorm:"default:DefaultImageURL" json:"url"` + PageBackgroundURL string `gorm:"default:DefaultImageURL" json:"backgroundURL"` }wire_gen.go (1)
19-40
: Consider reducing service coupling and improving modularity.The dependency graph shows high coupling between services. Consider:
- Breaking down large services into smaller, focused ones
- Using interfaces to reduce direct dependencies
- Implementing facade pattern for complex service interactions
Example approach:
// Define clear service boundaries type PostService interface { CreatePost(ctx context.Context, post *models.Post) error // ... other post-related methods } type UserService interface { GetUser(ctx context.Context, id string) (*models.User, error) // ... other user-related methods } // Use facade pattern for complex interactions type UserPostFacade struct { posts PostService users UserService } func NewUserPostFacade(posts PostService, users UserService) *UserPostFacade { return &UserPostFacade{posts: posts, users: users} }dao/user.go (1)
59-62
: Enhance SearchUserid function to return user data.The function currently only checks existence but could be more useful by returning the found user data.
-func (ud *UserDao) SearchUserid(UserID string) error { +func (ud *UserDao) SearchUserid(UserID string) (*models.User, error) { var User models.User - return ud.db.Where("id = ?", UserID).First(&User).Error + if err := ud.db.Where("id = ?", UserID).First(&User).Error; err != nil { + return nil, err + } + return &User, nil }dao/interface.go (1)
77-89
: Consider adding methods for user deletion and suspension.The UserDaoInterface could benefit from additional methods for user account management.
Add these methods to the interface:
type UserDaoInterface interface { // ... existing methods ... + DeleteUser(UserID string) error + SuspendUser(UserID string, until time.Time) error + ReactivateUser(UserID string) error }docs/swagger.yaml (1)
1155-1194
: Alter Email Endpoint – Summary Mismatch
The endpoint /api/{userid}/userpage/alteremail (lines 1155–1194) appears to validate new email addresses and update the user’s email. However, the summary text currently reads “验证验证码” even though the description suggests the endpoint modifies the email address. Consider updating the summary (e.g. “修改邮箱地址”) to more accurately reflect its function.controllers/user.go (1)
470-487
: Add username validation and rate limiting.The current implementation needs additional validation:
- Username format validation
- Profanity check
- Rate limiting for username changes
Apply this diff to add validation:
func (uc *UserControllers) ChangeUsername(c *gin.Context) { var User models.User if err := c.BindJSON(&User); err != nil { c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) return } User.ID = c.Param("userid") if User.ID == "" { c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) return } + // Validate username format + if !isValidUsernameFormat(User.Username) { + c.JSON(http.StatusBadRequest, models.Write("Invalid username format")) + return + } + // Check for profanity + if containsProfanity(User.Username) { + c.JSON(http.StatusBadRequest, models.Write("Username contains inappropriate content")) + return + } + // Check rate limiting + if isRateLimited(User.ID, "username_change") { + c.JSON(http.StatusTooManyRequests, models.Write("Too many username change attempts")) + return + } if err := uc.UserService.ChangeUsername(User.ID, User.Username); err != nil { c.JSON(http.StatusInternalServerError, models.Write("更新用户名失败")) return } c.JSON(http.StatusCreated, gin.H{"Message": "更新用户名成功!", "NewUsername": User.Username}) }.gitignore (1)
1-5
: Review configuration management approach.The shift from
.env
toconfig.yaml
suggests a change in configuration management:
- Ensure sensitive data is not committed to version control
- Document the configuration structure in README
- Provide a sample config file (e.g.,
config.yaml.example
)docs/swagger.json (1)
150-179
: Standardize HTTP status codes in API responses.Inconsistent use of status codes:
/api/getToken
uses 200 for success while similar endpoints use 201/api/logout
uses 201 for success but should use 200 as no resource is createdStandardize status codes according to HTTP specifications:
- Use 200 for successful GET requests
- Use 201 for successful resource creation
- Use 204 for successful requests with no content
Also applies to: 332-375
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sum
is excluded by!**/*.sum
📒 Files selected for processing (31)
.gitignore
(1 hunks)controllers/like.go
(7 hunks)controllers/post.go
(6 hunks)controllers/user.go
(1 hunks)controllers/wire.go
(1 hunks)dao/dao.go
(1 hunks)dao/interface.go
(1 hunks)dao/likes.go
(2 hunks)dao/post.go
(5 hunks)dao/user.go
(2 hunks)dao/wire.go
(1 hunks)docs/docs.go
(35 hunks)docs/swagger.json
(35 hunks)docs/swagger.yaml
(14 hunks)go.mod
(5 hunks)main.go
(1 hunks)middleware/middleware.go
(0 hunks)models/likes.go
(0 hunks)models/post.go
(3 hunks)models/user.go
(2 hunks)routes/post.go
(1 hunks)routes/userpage.go
(2 hunks)routes/wire.go
(1 hunks)services/email.go
(1 hunks)services/like.go
(7 hunks)services/post.go
(4 hunks)services/token.go
(1 hunks)services/user.go
(2 hunks)services/wire.go
(1 hunks)wire.go
(1 hunks)wire_gen.go
(1 hunks)
💤 Files with no reviewable changes (2)
- middleware/middleware.go
- models/likes.go
✅ Files skipped from review due to trivial changes (1)
- controllers/wire.go
🧰 Additional context used
🪛 golangci-lint (1.62.2)
dao/dao.go
18-18: Error return value of db.AutoMigrate
is not checked
(errcheck)
services/like.go
436-436: Error return value of ls.ld.SyncFollowMessageToDB
is not checked
(errcheck)
454-454: Error return value of ls.ld.DeleteFollowMessage
is not checked
(errcheck)
504-504: ineffectual assignment to count1
(ineffassign)
506-506: ineffectual assignment to count2
(ineffassign)
🔇 Additional comments (159)
services/post.go (6)
6-6
: Imports look good.
No immediate issues with these newly added imports. They appear necessary for the new functionality (reading files, working with context, time, etc.).Also applies to: 9-10, 12-14
19-21
: Great switch to interfaces for better testability and flexibility.
Replacing pointers to concrete DAOs with interface types is a commendable design choice, allowing seamless mocking and improved modularity.Also applies to: 24-24
114-114
: Swap logic acknowledged.
Using tuple swapping for sorting is straightforward and valid. This improves readability compared to manual temp variables.
155-160
: New GetPostByID method clarity.
Returning the post by ID is straightforward. Ensure input validation handles empty or invalid PostID.
168-169
: Tag-based filtering for unread messages.
This parameter enhancement is consistent with the new requirement to categorize messages by tag.
186-200
: File reading and YAML decoding.
The logic looks sound, with proper file closure and YAML unmarshalling. Watch out for partial reads if the file is corrupted, but otherwise good.dao/likes.go (9)
78-78
: User like count sync.
This single-field update is fine, though consider concurrency if multiple services update the same field concurrently.
168-169
: New tag support for searching unread messages.
Adds flexibility to filter user messages by tag. Looks correct.
176-179
: UpdateMessageStatus with tag.
Effectively sets all messages matching (UserID, Tag) to "read." Make sure partial updates are intended, or consider more granular filters if needed.
181-185
: SyncUserFollowersToDB.
Updates the follower count in the User table. Ensure no race conditions with other writes to the same field.
187-191
: SyncUserFolloweesToDB.
Similar to SyncUserFollowersToDB, concurrency handling is needed if this field is updated elsewhere.
193-196
: Insert follow message.
Creating a new follow record in the database. Straightforward approach.
198-201
: Delete follow message.
Deletes follow records by user ID. Confirm whether a more specific filter is needed if multiple follow relationships share the same user ID.
203-208
: SearchUserFollowee logic.
Retrieves IDs of users that the given user follows. Consider validating the returned slice for cases of no results.
210-215
: SearchUserFollower logic.
Retrieves user IDs of those who follow the given user. Consistent with naming and usage.services/like.go (11)
16-19
: Interface-based fields for LikeService.
Good step to allow mocking and more flexible testing.
21-23
: Constructor revised for interfaces.
Aligns seamlessly with the new interface-based design.
90-90
: Key format changed to "Poster:%s:likes".
Matches the rename for storing like counts. Ensure references reflect this new naming.
303-313
: InitMessage signature changes.
Added Tag and PostID usage. This method is straightforward, but ensure message scoping is correct for the new fields.
515-529
: SyncFollowCount method.
Captures the up-to-date follow/follower info from Redis. Looks reasonable. Remember to handle partial errors or concurrency edge cases.
531-541
: SyncLikeCount method.
Synchronizes user’s total likes from Redis to DB. Implementation is consistent with other syncs.
575-579
: GetPostLikeStatus addition.
Utility function checks membership in the “like_users” set. Straightforward approach.
581-585
: GetPostSaveStatus addition.
Consistent with the approach in GetPostLikeStatus.
587-591
: GetCommentLikeStatus addition.
Follows the same set-membership approach.
593-597
: GetReplyLikeStatus addition.
Same pattern for reply-likes membership.
599-603
: GetFollowStatus addition.
Checks if the user is a member of the followee’s “followers” set. Good for quick lookups.controllers/post.go (14)
6-6
: Use of "encoding/json" is appropriate
190-190
: No functional changes
362-362
: Good consolidated parameter retrieval
456-466
: Docstring updated to reflect 'GetUserUnreadLikeMessage'
This improved clarity is helpful.
467-467
: Renaming method accurately represents its scope
473-481
: Asynchronous update of message status
Launching a goroutine to update the message status in the background can improve responsiveness, but ensure potential errors from UpdateMessageStatus are at least logged.
482-482
: No functional changes
483-485
: Doc update for 'GetUserUnreadCommentMessage'
509-509
: No functional changes
510-520
: Doc updates for 'GetUserUnreadFollowMessage'
536-536
: No functional changes
537-537
: Doc added for 'GetToken'
545-545
: New method 'GetToken'
546-556
: Robust error handling for config read & token generation
Implementation is clear and covers failure points.controllers/like.go (23)
47-48
: Notification message is well-structured
Consider whether more detailed error logs or user-facing messages should be returned.
64-64
: Endpoint name update is consistent
79-80
: Docstring clarifies broader user data scope
85-88
: Enhanced doc for response codes
266-266
: Docs updated to include 'postid'
274-275
: Validating post ID
284-286
: Partial error handling
At least the service call error is caught here.
289-289
: Async message initialization
349-350
: Meaningful notification
Implementation is consistent with the pattern used elsewhere.
455-466
: New doc annotations for follow user
467-485
: Follow user logic
The code is straightforward; consider more detailed logging on failures.
486-497
: Documentation for unfollow route
498-509
: Unfollow logic
Implementation mirrored from follow.
511-521
: Docs for retrieving followee list
535-545
: Documentation for 'GetFollowerList'
546-557
: Consistent approach for fetching followers
559-569
: Docs for retrieving post status
581-581
: Doc annotation
592-600
: Retrieving comment like status
No immediate concerns if error cases are handled internally.
602-602
: Doc update
613-621
: Similar logic to 'GetCommentStatus'
No issues if errors are handled inside the service layer.
623-623
: Doc addition
624-632
: Doc changesdocs/docs.go (45)
156-185
: New doc block: /api/getToken
The documentation accurately reflects the "GetToken" endpoint.
578-629
: Renamed endpoint for comment messages
Documentation clarifies the message update logic.
630-681
: New endpoint for follow messages
Matches the changes for follow notifications.
682-733
: New endpoint for like messages
Documentation matches the updated logic.
734-777
: Campus endpoint doc
Reflects new route details.
779-823
: Food endpoint doc
Accurately updated.
824-868
: Life endpoint doc
Implementation consistent with code changes.
869-913
: Paint endpoint doc
No issues found.
914-967
: Publish post doc
Clear explanation of request and response details.
968-1012
: Recommend endpoint doc
Well detailed success/failure states.
1013-1057
: Get post detail doc
Consistent with the updated controller logic.
1058-1108
: Cancel like doc
Implementation is consistent with the revised route.
1109-1159
: Cancel save doc
Endpoint documentation matches the controller changes.
1160-1203
: Delete comment doc
Ensure doc summary precisely aligns with actual route usage.
1204-1242
: Get post counts doc
No further concerns.
1243-1288
: Get post status doc
Implementation is easy to understand.
1289-1339
: Like post doc
Route documented thoroughly.
1340-1391
: Publish comment doc
Description is accurate and up to date.
1392-1442
: Cancel comment like doc
No issues found.
1482-1527
: Get comment status doc
Matches newly added route references.
1528-1585
: Like comment doc
Documentation parallels the controller changes.
1586-1643
: Publish reply doc
Consistent with new reply publishing logic.
1644-1687
: Delete reply doc
No issues found.
1688-1738
: Cancel reply like doc
Implementation reflected in controllers.
1739-1777
: Get reply counts doc
Documentation accurate for new functionality.
1778-1823
: Get reply status doc
No concerns identified.
1824-1881
: Like reply doc
Matches the newly introduced method.
1882-1935
: Alter background doc
Implementation references user background updates.
1936-1995
: Alter email doc
Ensure correct email verification.
1996-2049
: Alter user image doc
No issues detected.
2050-2102
: Alter password doc
Implementation references user security.
2103-2156
: Alter username doc
No concerns.
2157-2200
: Get user data doc
Reflects retrieving user stats properly.
2201-2245
: Followee list doc
Aligns with code changes.
2246-2290
: Follower list doc
No issues found.
2291-2335
: Like record doc
Implementation is consistent with code.
2336-2379
: Delete single post doc
Matches the 'DeletePost' logic.
2380-2423
: Delete multiple posts doc
Reflects 'DeletePosts' approach.
2424-2468
: Save record doc
Route doc is consistent with controllers.
2469-2514
: Bind new email doc
Covers sending and verifying email.
2515-2559
: View record doc
No issues found.
2560-2610
: Cancel follow doc
Matches the controller route.
2611-2667
: Follow user doc
Implementation is consistent.
2668-2713
: Get follow status doc
No issues identified.
2888-2905
: New user fields for backgroundURL, followeeCount, followerCount, and likeCount
These added attributes expand the user model meaningfully.routes/wire.go (1)
1-9
: LGTM! Clean dependency injection setup.The
ProviderSet
correctly aggregates the service constructors using Wire's dependency injection pattern.dao/wire.go (1)
1-11
: LGTM! Clean dependency injection setup.The
ProviderSet
correctly aggregates the DAO providers and database initialization using Wire's dependency injection pattern.wire.go (1)
1-26
: LGTM! Clean dependency injection setup.The
InitializeApp
function correctly aggregates all provider sets and follows Wire's dependency injection pattern. The build tags and imports are properly configured.main.go (1)
30-33
: LGTM! Good use of dependency injection.The main function is now cleaner and more maintainable, with dependencies properly managed through Wire.
routes/userpage.go (3)
14-14
: LGTM! Good addition of UserControllers dependency.The addition of UserControllers as a dependency follows good dependency injection practices.
17-23
: LGTM! Constructor properly updated.The constructor is correctly updated to handle the new UserControllers dependency.
36-51
: Verify error handling in new routes.The new routes look good and align with the PR objectives. However, ensure proper error handling is implemented in the controller methods, especially for critical operations like password changes and email updates.
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Search for error handling patterns in the controller methods echo "Checking error handling in UserControllers methods..." ast-grep --pattern 'func (uc *UserControllers) $_($$) { $$$ if err != nil { $$$ } $$$ }'Length of output: 219
I'll run another script to inspect the definitions of the critical controller functions, particularly ChangeUserPassword and ChangeUserEmail, and see if error handling (e.g. checking for an error using "if err !=") is implemented in these functions.
🏁 Script executed:
#!/bin/bash echo "Searching for ChangeUserPassword with context..." rg -A 10 "func.*ChangeUserPassword" -n echo "Searching for ChangeUserEmail with context..." rg -A 10 "func.*ChangeUserEmail" -nLength of output: 3755
Subject: Error Handling in Critical Routes Confirmed
The inspection confirms that both ChangeUserPassword and ChangeUserEmail methods include proper error handling:
- In ChangeUserPassword (controllers/user.go:379-389), JSON binding errors and missing user ID are correctly caught, and the corresponding service function checks encryption and DAO update errors.
- Similarly, in ChangeUserEmail (controllers/user.go:435-445), invalid JSON input and absent user ID trigger error responses, with service and DAO layers propagating any update errors.
Overall, error handling for these critical routes is consistent and thorough.
routes/post.go (1)
51-54
: LGTM! Good addition of status endpoints.The new endpoints for retrieving token and status information are well-structured and follow consistent naming patterns.
Ensure these endpoints are properly documented in the API documentation.
models/post.go (2)
28-29
: LGTM! Good addition of fields for message tracking.The addition of PostID and Tag fields to the Message struct improves message tracking capabilities.
86-91
: Consider security implications of QiNiuYun configuration.The QiNiuYunConfig struct contains sensitive credentials. Ensure these values are properly secured and not committed to version control.
Check if sensitive credentials are accidentally committed:
Consider using environment variables or a secure secrets management system for these credentials.
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Search for potential QiNiuYun credentials in the codebase echo "Checking for hardcoded QiNiuYun credentials..." rg -i "access_key|secret_key" --type yamlLength of output: 146
I'll now run an additional script that searches the entire repository (not limited to YAML files) for any hardcoded QiNiuYun credential elements, including the struct usage.
🏁 Script executed:
#!/bin/bash # Comprehensive search for hardcoded QiNiuYun credentials in the repository echo "Searching for QiNiuYun credential keywords across all files..." # Use \b to match complete words where possible. rg -i "AccessKey\\b|SecretKey\\b|Bucket\\b|Domain\\b" . echo "Searching for references to QiNiuYunConfig struct..." rg -i "QiNiuYunConfig" .Length of output: 1176
Security Verification: QiNiuYunConfig Usage is Consistent with Runtime Configuration
The search results revealed only the definition and usage of the QiNiuYunConfig struct without any actual hardcoded credentials in the repository. The sensitive fields (AccessKey, SecretKey, etc.) are read from a configuration file (evidenced by the ReadConfig function) rather than being embedded as literals in the source code.
Nevertheless, remain cautious with the configuration file itself—ensure it's excluded from version control (e.g., via .gitignore) and consider using environment variables or a secrets management solution to further protect these credentials.
services/email.go (1)
13-16
: LGTM! Good use of interface-based design.The change from concrete types to interfaces improves testability and flexibility.
dao/interface.go (1)
9-20
: LGTM! Well-structured provider pattern implementation.The provider functions are well-organized and follow the dependency injection pattern.
dao/post.go (4)
58-61
: LGTM! Improved error handling.The changes to use
First
instead of directWhere
queries improve error handling by properly returninggorm.ErrRecordNotFound
when no records are found. This aligns better with GORM's best practices.Also applies to: 64-67, 77-80
167-169
: LGTM! Improved handling of empty record sets.The changes prevent SQL errors when using
NOT IN
with an empty slice by appending an empty string toRecordID
when it's nil. This is a good defensive programming practice.Also applies to: 190-192
30-30
: Verify soft delete behavior.The change in deletion method from
Delete(&models.PostMessage{}, ...)
toModel(&models.PostMessage{}).Delete(...)
might affect how GORM handles soft deletes. Please ensure that soft deletes work as expected if thePostMessage
model has thegorm.DeletedAt
field.Run the following script to check if the model has soft delete support:
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Description: Check if PostMessage model has soft delete support. ast-grep --pattern $'type PostMessage struct { $$$ DeletedAt $_ `gorm:"$$$"` $$$ }'Length of output: 90
I'll generate a new shell script to search for the PostMessage struct definition and directly check for any soft delete related field (specifically, the presence of a DeletedAt field with a gorm tag) within it.
🏁 Script executed:
#!/bin/bash # Step 1: Find the definition of the PostMessage struct echo "Searching for 'PostMessage' struct definition with context:" rg "type PostMessage struct {" -A 40 # Step 2: Check if there's a DeletedAt field with a gorm tag (indicating soft delete support) echo -e "\nSearching for a 'DeletedAt' field with a gorm tag:" rg "DeletedAt.*gorm:" -nLength of output: 437
I'll generate a new shell script using fixed string searches (to avoid regex errors) and also attempt to locate the file where the PostMessage model is defined. This will help ensure we can determine if the model has soft delete support via a DeletedAt field.
🏁 Script executed:
#!/bin/bash # Step 1: Search for the file that likely defines PostMessage (e.g., post_message.go) echo "Searching for file(s) containing 'PostMessage':" fd -HI -e go -x grep -H "type PostMessage struct" {} # Step 2: Use fixed-string search to show the PostMessage struct definition context. echo -e "\nDisplaying context around 'type PostMessage struct {' using fixed string search:" rg -F "type PostMessage struct {" -A 40 # Step 3: Search within the repository for any line containing 'DeletedAt' with indication of a gorm tag. echo -e "\nSearching for 'DeletedAt' with a gorm tag using fixed string search:" rg -F "DeletedAt" -nLength of output: 2322
Confirmed soft delete behavior is not affected.
The PostMessage model (located in models/post.go) does not include a DeletedAt field, meaning soft deletes aren’t enabled for this entity. As a result, the change in deletion method does not alter soft delete behavior.
86-86
: Verify soft delete behavior.Similar to
DeletePostBody
, the change in deletion method might affect how GORM handles soft deletes. Please ensure that soft deletes work as expected if theComment
model has thegorm.DeletedAt
field.Run the following script to check if the model has soft delete support:
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Description: Check if Comment model has soft delete support. ast-grep --pattern $'type Comment struct { $$$ DeletedAt $_ `gorm:"$$$"` $$$ }'Length of output: 86
I'm not seeing the expected output from the initial ast-grep command. Let's run additional commands to check for the Comment model definition and look explicitly for any soft delete field configuration (i.e. any use of "DeletedAt" with a gorm tag).
🏁 Script executed:
#!/bin/bash echo "Searching for Comment model definition with context..." rg -C 5 "type Comment struct" . echo "" echo "Searching for DeletedAt field with gorm tag in the repository..." rg -C 2 'DeletedAt.*gorm:"' .Length of output: 895
Soft delete functionality not enabled.
The Comment model (in models/post.go) does not define a DeletedAt field, so soft deletes are not activated. The new deletion method, therefore, is performing a hard delete as intended. If soft deletes are later required, the model should be updated to include a DeletedAt field.docs/swagger.yaml (33)
115-126
: User Model Enhancements
New properties have been introduced in the models.User definition – namely, backgroundURL (lines 115–116), followeeCount and followerCount (lines 119–122), and likeCount (lines 125–126). These additions align with the new user profile features. Please verify that all related controller code, database fields, and UI components consistently use the same names and types.
143-178
: Comment Message Endpoint Addition
A new GET endpoint is added at /api/{userid}/commentmessage (lines 143–178) to retrieve unread comment notifications and update their status to read. The overall structure (consumes, produces, response codes such as 200, 207, 400, and 500) looks sound. One point to verify: the use of status code “207” for “状态更新错误” is unusual – please confirm that this custom code is intentional and documented.
178-212
: Follow Message Endpoint Addition
The changes introduce a GET endpoint at /api/{userid}/followmessage (lines 178–212) that retrieves unread “follow” notifications. The descriptions, parameters, and responses are consistent with similar endpoints.
213-247
: Like Message Endpoint Addition
A new GET endpoint at /api/{userid}/likemessage (lines 213–247) is included to fetch unread like messages. The endpoint’s configuration and response schemas match the pattern seen in the other message endpoints.
367-397
: Reply Like Status Endpoint
At /api/{userid}/post/{postid}/{commentid}/{replyid}/getstatus (lines 367–397) the API now supports fetching the like status for a reply. The definition (consumes, produces, parameters, and response schema) is clear. Verify that the client side expects the “additionalProperties” style response.
497-527
: Comment Like Status Endpoint
The GET endpoint /api/{userid}/post/{postid}/{commentid}/getstatus (lines 497–527) has been added to obtain the like status for a comment. The configuration is analogous to the reply status endpoint.
1016-1049
: Cancel Follow Endpoint
The new POST endpoint /api/{userid}/userpage/{followid}/cancelfollow (lines 1016–1049) for unfollowing a user appears well defined, with clear path parameters and a 201 response code on success.
1050-1087
: Follow User Endpoint
At /api/{userid}/userpage/{followid}/follow (lines 1050–1087), the API allows following another user while also uploading a follow-related message. In addition to the expected 201, a 207 response is provided for cases where message upload fails but focus action succeeds; please double-check that this pattern is documented for clients.
1088-1116
: Get Follow Status Endpoint
The GET endpoint /api/{userid}/userpage/{followid}/getstatus (lines 1088–1116) returns the follow status between users. The structure is straightforward; ensure that the “additionalProperties” response scheme is fully supported on the client side.
1119-1154
: Alter Background Endpoint
The POST endpoint /api/{userid}/userpage/alterbackground (lines 1119–1154) for updating the user’s personal homepage background image is clear and consistent.
1195-1227
: Alter Image Endpoint
The POST endpoint /api/{userid}/userpage/alterimage (lines 1195–1227) for updating the user’s avatar is well configured with the expected request/response structure.
1231-1263
: Alter Password Endpoint
The password change endpoint /api/{userid}/userpage/alterpassword (lines 1231–1263) is clear and follows the same design pattern as the other personal profile modifications.
1266-1299
: Alter Username Endpoint
The POST endpoint /api/{userid}/userpage/alterusername (lines 1266–1299) for changing the username is straightforward and consistent with the other profile endpoints.
1302-1328
: User Count Endpoint
The GET endpoint /api/{userid}/userpage/count (lines 1302–1328) returns various user statistics such as like, follow, and fan counts. Verify that the returned data directly corresponds to the new properties (e.g. followeeCount, followerCount, likeCount) added in the User model.
1331-1360
: Followee List Endpoint
The GET endpoint /api/{userid}/userpage/followeelist (lines 1331–1360) that retrieves the list of users the current user is following is defined clearly.
1361-1390
: Follower List Endpoint
Likewise, the GET endpoint /api/{userid}/userpage/followerlist (lines 1361–1390) returns the list of a user’s followers accurately.
1391-1418
: Like Record Endpoint
The new GET endpoint /api/{userid}/userpage/likerecord (lines 1391–1418) provides historical like records over one month. Its request and response structures appear consistent with similar endpoints.
1421-1449
: Delete Post Endpoint
The DELETE endpoint /api/{userid}/userpage/mypost/delete/{postid} (lines 1421–1449) for deleting an individual post is clear and uses proper response codes.
1450-1476
: Bulk Delete Posts Endpoint
The bulk delete endpoint /api/{userid}/userpage/mypost/deleteposts (lines 1450–1476) is designed similarly to the single delete endpoint. Its request/response format meets the expected structure.
1479-1508
: Save Record Endpoint
The GET endpoint /api/{userid}/userpage/saverecord (lines 1479–1508) that retrieves a user’s historical collection records is well defined.
1509-1538
: Send Email Verification for User Page
The endpoint /api/{userid}/userpage/sendemail (lines 1509–1538) to bind a new email address is added with suitable request and response schemas.
1539-1568
: View Record Endpoint
The GET endpoint /api/{userid}/userpage/viewrecord (lines 1539–1568) retrieves a user’s historical browsing records. The definition is clear and consistent.
1659-1678
: Get Token Endpoint
A new GET endpoint /api/getToken (lines 1659–1678) is introduced for token retrieval (targeted at ‘图床’). Its response (object with additionalProperties) should be verified against the client’s expectations.
1679-1713
: Password Login Endpoint
The POST endpoint /api/login/bypassword (lines 1679–1713) for logging in with email and password is standard and appears correct.
1714-1744
: Login Send Email Endpoint
The POST endpoint /api/login/sendemail (lines 1714–1744) sends a verification code for login. Its setup compares well with similar endpoints.
1748-1776
: Login Verify Code Endpoint
The endpoint /api/login/sendemail/verifycode (lines 1748–1776) verifies the user’s code as part of the login process and returns the token if successful. The structure and response format are as expected.
1779-1807
: Logout Endpoint
The POST endpoint /api/logout (lines 1779–1807) forces token expiration to log the user out. This change is clear and mirrors the corresponding YAML documentation.
1808-1838
: Post Save Endpoint
The POST endpoint /api/posts/{postid}/{userid}/save (lines 1808–1838) lets users save a post (adding to favorites) by incrementing the save count. The parameters and response schema are consistent.
1841-1870
: Register Send Email Endpoint
The endpoint /api/register/sendemail (lines 1841–1870) determines if the user is already registered and sends a verification code accordingly. The response structure is well defined.
1876-1905
: Register Verify Code Endpoint
The POST endpoint at /api/register/sendemail/verifycode (lines 1876–1905) validates the code and, upon success, returns the token and user information. It is in line with the new registration flow.
2554-2604
: Cancel Follow Endpoint (JSON)
The POST endpoint /api/{userid}/userpage/{followid}/cancelfollow (lines 2554–2604) in the JSON version cleanly mirrors its YAML counterpart. The structure and status responses are consistent.
2605-2661
: Follow User Endpoint (JSON)
The POST endpoint /api/{userid}/userpage/{followid}/follow (lines 2605–2661) is well defined; it even accounts for potential conflicts (409) when the user is already followed.
2662-2707
: Get Follow Status (JSON)
The GET endpoint /api/{userid}/userpage/{followid}/getstatus (lines 2662–2707) returns the follow status data. The response schema using an object with additionalProperties appears consistent.controllers/user.go (1)
338-366
: Apply similar validation for profile picture URL.This method has similar validation needs as ChangeUserBackground.
Please apply the same validation improvements suggested for the background image URL:
- URL format validation
- Image size/dimension limits
- Input sanitization
go.mod (1)
6-48
: Verify dependency versions and security.Please verify the following:
- Check for known vulnerabilities in jwt-go v3.2.0
- Consider upgrading to golang-jwt/jwt for better security
- Ensure wire v0.6.0 is compatible with the project's Go version
// 获取用户关注数和粉丝数 | ||
func (ls *LikeService) GetFollowCount(UserID string) (int, int, error) { | ||
var count1, count2 int | ||
key1 := "User:followers" | ||
key2 := "User:followees" | ||
followerscount, err1 := utils.Client.HGet(utils.Ctx, key1, UserID).Result() | ||
followeescount, err2 := utils.Client.HGet(utils.Ctx, key2, UserID).Result() | ||
if err1 == redis.Nil { | ||
count1 = 0 | ||
} else if err2 == redis.Nil { | ||
count2 = 0 | ||
} else if err1 != nil || err2 != nil { | ||
return 0, 0, fmt.Errorf("get follow counts error:%v\t%v", err1, err2) | ||
} | ||
count1, _ = strconv.Atoi(followerscount) | ||
count2, _ = strconv.Atoi(followeescount) | ||
return count1, count2, 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.
🛠️ Refactor suggestion
GetFollowCount has ineffectual assignments on lines 504 and 506.
The conditions set count1 = 0 and count2 = 0, but they are overwritten by the final conversion at lines 510 and 511. Remove or rethink the assignments to avoid confusion.
🧰 Tools
🪛 golangci-lint (1.62.2)
504-504: ineffectual assignment to count1
(ineffassign)
506-506: ineffectual assignment to count2
(ineffassign)
// 用户关注操作 | ||
func (ls *LikeService) Follow(UserID, FolloweeID string) error { | ||
key := fmt.Sprintf("User:%s:followers", FolloweeID) | ||
//查找关注记录以避免重复关注 | ||
if utils.Client.SIsMember(utils.Ctx, key, UserID).Val() { | ||
return fmt.Errorf("the user %s is already followed user %s", UserID, FolloweeID) | ||
} | ||
//添加用户到粉丝合集 | ||
utils.Client.SAdd(utils.Ctx, key, UserID) | ||
//更新用户关注数 | ||
key = "User:followees" | ||
utils.Client.HIncrBy(utils.Ctx, key, UserID, 1) | ||
Record := models.FollowMessage{ | ||
FollowerID: UserID, | ||
FolloweeID: FolloweeID, | ||
} | ||
go ls.ld.SyncFollowMessageToDB(&Record) | ||
key = "User:followers" | ||
utils.Client.HIncrBy(utils.Ctx, key, FolloweeID, 1) | ||
return 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.
Follow method missing error handling on SyncFollowMessageToDB.
The static analysis warns the returned error from line 436 is unhandled. This can silently swallow DB insertion failures.
Apply the fix by capturing and handling the error:
-go ls.ld.SyncFollowMessageToDB(&Record)
+if err := ls.ld.SyncFollowMessageToDB(&Record); err != nil {
+ // handle or log error
+}
🧰 Tools
🪛 golangci-lint (1.62.2)
436-436: Error return value of ls.ld.SyncFollowMessageToDB
is not checked
(errcheck)
// 用户取消关注操作 | ||
func (ls *LikeService) CancelFollow(UserID, FolloweeID string) error { | ||
key := fmt.Sprintf("User:%s:followers", FolloweeID) | ||
//查找关注记录以避免重复关注 | ||
if !utils.Client.SIsMember(utils.Ctx, key, UserID).Val() { | ||
return fmt.Errorf("the user %s is not followed user %s", UserID, FolloweeID) | ||
} | ||
//用户移除粉丝合集 | ||
utils.Client.SRem(utils.Ctx, key, UserID) | ||
//更新用户关注数 | ||
key = "User:followees" | ||
utils.Client.HIncrBy(utils.Ctx, key, UserID, -1) | ||
go ls.ld.DeleteFollowMessage(UserID) | ||
key = "User:followers" | ||
utils.Client.HIncrBy(utils.Ctx, key, FolloweeID, -1) | ||
return 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.
CancelFollow method missing error handling on DeleteFollowMessage.
Similarly, the returned error from line 454 is unhandled, creating potential silent failures.
-go ls.ld.DeleteFollowMessage(UserID)
+if err := ls.ld.DeleteFollowMessage(UserID); err != nil {
+ // handle or log error
+}
📝 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 (ls *LikeService) CancelFollow(UserID, FolloweeID string) error { | |
key := fmt.Sprintf("User:%s:followers", FolloweeID) | |
//查找关注记录以避免重复关注 | |
if !utils.Client.SIsMember(utils.Ctx, key, UserID).Val() { | |
return fmt.Errorf("the user %s is not followed user %s", UserID, FolloweeID) | |
} | |
//用户移除粉丝合集 | |
utils.Client.SRem(utils.Ctx, key, UserID) | |
//更新用户关注数 | |
key = "User:followees" | |
utils.Client.HIncrBy(utils.Ctx, key, UserID, -1) | |
go ls.ld.DeleteFollowMessage(UserID) | |
key = "User:followers" | |
utils.Client.HIncrBy(utils.Ctx, key, FolloweeID, -1) | |
return nil | |
} | |
// 用户取消关注操作 | |
func (ls *LikeService) CancelFollow(UserID, FolloweeID string) error { | |
key := fmt.Sprintf("User:%s:followers", FolloweeID) | |
//查找关注记录以避免重复关注 | |
if !utils.Client.SIsMember(utils.Ctx, key, UserID).Val() { | |
return fmt.Errorf("the user %s is not followed user %s", UserID, FolloweeID) | |
} | |
//用户移除粉丝合集 | |
utils.Client.SRem(utils.Ctx, key, UserID) | |
//更新用户关注数 | |
key = "User:followees" | |
utils.Client.HIncrBy(utils.Ctx, key, UserID, -1) | |
if err := ls.ld.DeleteFollowMessage(UserID); err != nil { | |
// handle or log error | |
} | |
key = "User:followers" | |
utils.Client.HIncrBy(utils.Ctx, key, FolloweeID, -1) | |
return nil | |
} |
🧰 Tools
🪛 golangci-lint (1.62.2)
454-454: Error return value of ls.ld.DeleteFollowMessage
is not checked
(errcheck)
PostMessage, _ := pc.PostService.GetPostByID(PostID) | ||
CommenterID, CommentBody, _ := pc.LikeService.SearchCommentByID(CommentID) | ||
User, _ := pc.UserService.UserDao.GetUserFromID(UserID) | ||
message := fmt.Sprintf("用户%s回复了你在帖子%s的评论!", User.Username, PostMessage.Title) | ||
if err := pc.LikeService.InitMessage(CommentMessage.CommenterID, message, User.ImageURL); err != nil { | ||
message := fmt.Sprintf("用户%s回复了你在帖子%s的评论:\n%s", User.Username, PostMessage.Title, CommentBody) | ||
if err := pc.LikeService.InitMessage(CommenterID, message, User.ImageURL, "评论", PostID); err != 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.
🛠️ Refactor suggestion
Check returned errors for robust error handling
In the event these calls fail, the subsequent logic may cause runtime issues or produce incomplete notifications.
PostMessage, _ := pc.PostService.GetPostByID(PostID) | ||
User, _ := pc.UserService.GetUserFromID(UserID) | ||
message := fmt.Sprintf("用户%s评论了帖子:\n%s", User.Username, PostMessage.Title) | ||
if err := pc.LikeService.InitMessage(PostMessage.PosterID, message, User.ImageURL, "评论", PostID); err != nil { | ||
c.JSON(http.StatusMultiStatus, models.Write("评论处理成功,消息上传失败")) |
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
Handle potential errors from GetPostByID and GetUserFromID
If these calls fail, it could lead to nil pointer references or inconsistent data. It's recommended to check for errors.
Example suggestion:
PostMessage, err := pc.PostService.GetPostByID(PostID)
-if err != nil {
- // handle error
-}
User, err1 := pc.UserService.GetUserFromID(UserID)
-if err1 != nil {
- // handle error
-}
message := fmt.Sprintf("用户%s评论了帖子:\n%s", User.Username, PostMessage.Title)
...
Committable suggestion skipped: line range outside the PR's diff.
/api/{userid}/post/{postid}/cancellike: | ||
post: | ||
consumes: | ||
- application/json | ||
description: 用户取消点赞,点赞数减一 | ||
parameters: | ||
- description: 帖子ID | ||
in: path | ||
name: postid | ||
required: true | ||
type: string | ||
- description: 用户D | ||
in: path | ||
name: userid | ||
required: true | ||
type: string | ||
produces: | ||
- application/json | ||
responses: | ||
"201": | ||
description: 用户取消点赞成功 | ||
schema: | ||
$ref: '#/definitions/models.Response' | ||
"400": | ||
description: 输入无效 | ||
schema: | ||
$ref: '#/definitions/models.Response' | ||
"500": | ||
description: 取消点赞记录上传失败 | ||
schema: | ||
$ref: '#/definitions/models.Response' | ||
summary: 用户取消点赞帖子 | ||
tags: | ||
- 帖子-点赞 |
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.
Cancel Post Like Endpoint – Minor Typo
The POST endpoint /api/{userid}/post/{postid}/cancellike (lines 606–639) correctly defines the cancellation action; however, in the parameters the description for the user ID on line 617 is written “用户D” instead of “用户ID.” Please fix this typo to prevent confusion in the API documentation.
// @Summary 修改个人主页背景 | ||
// @Description 修改用户个人主页的背景图片 | ||
// @Tags 个人主页 | ||
// @Accept json | ||
// @Produce json | ||
// @Param userbackground body models.User true "新背景" | ||
// @Param userid path string true "用户ID" | ||
// @Success 201 {object} map[string]interface{} "响应成功信息以及背景图片的url" | ||
// @Failure 400 {object} models.Response "输入无效" | ||
// @Failure 500 {object} models.Response "修改背景失败" | ||
// @Router /api/{userid}/userpage/alterbackground [post] | ||
func (uc *UserControllers) ChangeUserBackground(c *gin.Context) { | ||
var UserBackground models.User | ||
if err := c.BindJSON(&UserBackground); err != nil { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
UserBackground.ID = c.Param("userid") | ||
if UserBackground.ID == "" { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
if err := uc.UserService.ChangeUserBackground(UserBackground.ID, UserBackground.PageBackgroundURL); err != nil { | ||
c.JSON(http.StatusInternalServerError, models.Write("修改背景失败!")) | ||
return | ||
} | ||
c.JSON(http.StatusCreated, gin.H{"message": "修改成功!", "newbackground": UserBackground.PageBackgroundURL}) | ||
} |
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
Add input validation for background image URL.
The current implementation lacks validation for the background image URL. Consider:
- URL format validation
- Image size/dimension limits
- Input sanitization
Apply this diff to add validation:
func (uc *UserControllers) ChangeUserBackground(c *gin.Context) {
var UserBackground models.User
if err := c.BindJSON(&UserBackground); err != nil {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
UserBackground.ID = c.Param("userid")
if UserBackground.ID == "" {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
+ // Validate URL format
+ if !isValidImageURL(UserBackground.PageBackgroundURL) {
+ c.JSON(http.StatusBadRequest, models.Write("Invalid image URL format"))
+ return
+ }
+ // Check image size/dimensions
+ if err := validateImageDimensions(UserBackground.PageBackgroundURL); err != nil {
+ c.JSON(http.StatusBadRequest, models.Write(err.Error()))
+ return
+ }
+ // Sanitize URL
+ UserBackground.PageBackgroundURL = sanitizeURL(UserBackground.PageBackgroundURL)
if err := uc.UserService.ChangeUserBackground(UserBackground.ID, UserBackground.PageBackgroundURL); err != nil {
c.JSON(http.StatusInternalServerError, models.Write("修改背景失败!"))
return
}
c.JSON(http.StatusCreated, gin.H{"message": "修改成功!", "newbackground": UserBackground.PageBackgroundURL})
}
📝 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.
// @Summary 修改个人主页背景 | |
// @Description 修改用户个人主页的背景图片 | |
// @Tags 个人主页 | |
// @Accept json | |
// @Produce json | |
// @Param userbackground body models.User true "新背景" | |
// @Param userid path string true "用户ID" | |
// @Success 201 {object} map[string]interface{} "响应成功信息以及背景图片的url" | |
// @Failure 400 {object} models.Response "输入无效" | |
// @Failure 500 {object} models.Response "修改背景失败" | |
// @Router /api/{userid}/userpage/alterbackground [post] | |
func (uc *UserControllers) ChangeUserBackground(c *gin.Context) { | |
var UserBackground models.User | |
if err := c.BindJSON(&UserBackground); err != nil { | |
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | |
return | |
} | |
UserBackground.ID = c.Param("userid") | |
if UserBackground.ID == "" { | |
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | |
return | |
} | |
if err := uc.UserService.ChangeUserBackground(UserBackground.ID, UserBackground.PageBackgroundURL); err != nil { | |
c.JSON(http.StatusInternalServerError, models.Write("修改背景失败!")) | |
return | |
} | |
c.JSON(http.StatusCreated, gin.H{"message": "修改成功!", "newbackground": UserBackground.PageBackgroundURL}) | |
} | |
// @Summary 修改个人主页背景 | |
// @Description 修改用户个人主页的背景图片 | |
// @Tags 个人主页 | |
// @Accept json | |
// @Produce json | |
// @Param userbackground body models.User true "新背景" | |
// @Param userid path string true "用户ID" | |
// @Success 201 {object} map[string]interface{} "响应成功信息以及背景图片的url" | |
// @Failure 400 {object} models.Response "输入无效" | |
// @Failure 500 {object} models.Response "修改背景失败" | |
// @Router /api/{userid}/userpage/alterbackground [post] | |
func (uc *UserControllers) ChangeUserBackground(c *gin.Context) { | |
var UserBackground models.User | |
if err := c.BindJSON(&UserBackground); err != nil { | |
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | |
return | |
} | |
UserBackground.ID = c.Param("userid") | |
if UserBackground.ID == "" { | |
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | |
return | |
} | |
// Validate URL format | |
if !isValidImageURL(UserBackground.PageBackgroundURL) { | |
c.JSON(http.StatusBadRequest, models.Write("Invalid image URL format")) | |
return | |
} | |
// Check image size/dimensions | |
if err := validateImageDimensions(UserBackground.PageBackgroundURL); err != nil { | |
c.JSON(http.StatusBadRequest, models.Write(err.Error())) | |
return | |
} | |
// Sanitize URL | |
UserBackground.PageBackgroundURL = sanitizeURL(UserBackground.PageBackgroundURL) | |
if err := uc.UserService.ChangeUserBackground(UserBackground.ID, UserBackground.PageBackgroundURL); err != nil { | |
c.JSON(http.StatusInternalServerError, models.Write("修改背景失败!")) | |
return | |
} | |
c.JSON(http.StatusCreated, gin.H{"message": "修改成功!", "newbackground": UserBackground.PageBackgroundURL}) | |
} |
// @Summary 修改个人主页密码 | ||
// @Description 修改用户个人主页的密码 | ||
// @Tags 个人主页 | ||
// @Accept json | ||
// @Produce json | ||
// @Param user body models.User true "新密码" | ||
// @Param userid path string true "用户ID" | ||
// @Success 201 {object} models.Response "修改密码成功" | ||
// @Failure 400 {object} models.Response "输入无效" | ||
// @Failure 500 {object} models.Response "修改密码成功" | ||
// @Router /api/{userid}/userpage/alterpassword [post] | ||
func (uc *UserControllers) ChangeUserPassword(c *gin.Context) { | ||
var User models.User | ||
if err := c.BindJSON(&User); err != nil { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
User.ID = c.Param("userid") | ||
if User.ID == "" { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
if err := uc.UserService.ChangeUserPassword(User.ID, User.Password); err != nil { | ||
c.JSON(http.StatusInternalServerError, models.Write(err.Error())) | ||
return | ||
} | ||
c.JSON(http.StatusCreated, models.Write("修改密码成功")) | ||
} |
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.
Add critical security measures for password change.
The current implementation lacks essential security measures:
- Password strength validation
- Old password verification
- Rate limiting for password changes
Apply this diff to enhance security:
func (uc *UserControllers) ChangeUserPassword(c *gin.Context) {
var User models.User
if err := c.BindJSON(&User); err != nil {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
User.ID = c.Param("userid")
if User.ID == "" {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
+ // Validate password strength
+ if err := validatePasswordStrength(User.Password); err != nil {
+ c.JSON(http.StatusBadRequest, models.Write(err.Error()))
+ return
+ }
+ // Verify old password
+ if err := uc.UserService.VerifyOldPassword(User.ID, User.OldPassword); err != nil {
+ c.JSON(http.StatusUnauthorized, models.Write("Old password is incorrect"))
+ return
+ }
+ // Check rate limiting
+ if isRateLimited(User.ID, "password_change") {
+ c.JSON(http.StatusTooManyRequests, models.Write("Too many password change attempts"))
+ return
+ }
if err := uc.UserService.ChangeUserPassword(User.ID, User.Password); err != nil {
c.JSON(http.StatusInternalServerError, models.Write(err.Error()))
return
}
+ // Invalidate all existing sessions
+ if err := uc.TokenService.InvalidateAllUserTokens(User.ID); err != nil {
+ log.Printf("Failed to invalidate user tokens: %v", err)
+ }
c.JSON(http.StatusCreated, models.Write("修改密码成功"))
}
Committable suggestion skipped: line range outside the PR's diff.
func (u *UserControllers) ChangeUserEmail(c *gin.Context) { | ||
var code models.Emailverify | ||
if err := c.BindJSON(&code); err != nil { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
UserID := c.Param("userid") | ||
if UserID == "" { | ||
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!")) | ||
return | ||
} | ||
if err := u.EmailService.VerifyCode(code.Code); err != nil { | ||
response := err.Error() | ||
c.JSON(http.StatusConflict, response) | ||
return | ||
} | ||
if err := u.UserService.ChangeUserEmail(UserID, code.Email); err != nil { | ||
c.JSON(http.StatusInternalServerError, models.Write("更新邮箱地址失败")) | ||
return | ||
} | ||
c.JSON(http.StatusCreated, gin.H{"message": "修改密码成功!", "newEmail": code.Email}) | ||
|
||
} |
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
Enhance email change security measures.
The current implementation needs additional security measures:
- Email format validation
- Check for existing email usage
- Notification to old email address
Apply this diff to improve security:
func (u *UserControllers) ChangeUserEmail(c *gin.Context) {
var code models.Emailverify
if err := c.BindJSON(&code); err != nil {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
UserID := c.Param("userid")
if UserID == "" {
c.JSON(http.StatusBadRequest, models.Write("输入无效,请重试!"))
return
}
+ // Validate email format
+ if !isValidEmailFormat(code.Email) {
+ c.JSON(http.StatusBadRequest, models.Write("Invalid email format"))
+ return
+ }
+ // Check if email is already in use
+ if u.UserService.IsEmailInUse(code.Email) {
+ c.JSON(http.StatusConflict, models.Write("Email already in use"))
+ return
+ }
if err := u.EmailService.VerifyCode(code.Code); err != nil {
response := err.Error()
c.JSON(http.StatusConflict, response)
return
}
+ // Get old email for notification
+ oldEmail, _ := u.UserService.GetUserEmail(UserID)
if err := u.UserService.ChangeUserEmail(UserID, code.Email); err != nil {
c.JSON(http.StatusInternalServerError, models.Write("更新邮箱地址失败"))
return
}
+ // Notify old email about the change
+ go u.EmailService.SendEmailChangeNotification(oldEmail)
c.JSON(http.StatusCreated, gin.H{"message": "修改密码成功!", "newEmail": code.Email})
}
Committable suggestion skipped: line range outside the PR's diff.
// @Summary 退出登录 | ||
// @Description 退出登录并将token强制过期 | ||
// @Tags 个人主页-退出登录 | ||
// @Accept application/json | ||
// @Produce application/json | ||
// @Param Authorization header string true "Bearer token" | ||
// @Success 201 {object} models.Response "登出成功" | ||
// @Failure 400 {object} models.Response "token获取失败" | ||
// @Failure 500 {object} models.Response "服务器错误" | ||
// @Router /api/logout [post] | ||
func (uc *UserControllers) Logout(c *gin.Context) { | ||
// 从请求头中获取token | ||
tokenString := c.GetHeader("Authorization") | ||
if tokenString == "" { | ||
c.JSON(http.StatusBadRequest, models.Write("token获取失败!")) | ||
return | ||
} | ||
if len(tokenString) > 7 && tokenString[:7] == "Bearer " { | ||
tokenString = tokenString[7:] | ||
} | ||
_, err := uc.TokenService.InvalidateToken(tokenString) | ||
if err != nil { | ||
c.JSON(http.StatusInternalServerError, models.Write(err.Error())) | ||
return | ||
} | ||
c.JSON(http.StatusCreated, models.Write("登出成功!")) | ||
} |
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
Enhance security in logout implementation.
Consider the following security improvements:
- Add token format validation before invalidation
- Add logging for security audit trail
- Consider implementing rate limiting for the logout endpoint
Apply this diff to enhance security:
func (uc *UserControllers) Logout(c *gin.Context) {
+ // Get token from Authorization header
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusBadRequest, models.Write("token获取失败!"))
return
}
+ // Validate token format
+ if !strings.HasPrefix(tokenString, "Bearer ") {
+ c.JSON(http.StatusBadRequest, models.Write("Invalid token format"))
+ return
+ }
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
+ // Validate token string format (e.g., JWT format)
+ if !isValidTokenFormat(tokenString) {
+ c.JSON(http.StatusBadRequest, models.Write("Invalid token format"))
+ return
+ }
+ // Log logout attempt
+ log.Printf("Logout attempt for token: %s", tokenString[:10]) // Log only first 10 chars for security
_, err := uc.TokenService.InvalidateToken(tokenString)
if err != nil {
+ log.Printf("Failed to invalidate token: %v", err)
c.JSON(http.StatusInternalServerError, models.Write(err.Error()))
return
}
+ // Log successful logout
+ log.Printf("Successful logout for token: %s", tokenString[:10])
c.JSON(http.StatusCreated, models.Write("登出成功!"))
}
Committable suggestion skipped: line range outside the PR's diff.
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.
很好捏,dao层还可以优化一下,其实多数情况下一个model只要crud四个方法就能完成大部分任务了
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.
好神秘的做法,跨层级了,为什么不抽象一个like服务?
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.
我去这么多方法,劳模!
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.
为什么不直接读取一个models.User,然后在service再去聚合呢?这样有很多重复逻辑都可以避免吧
@@ -18,34 +13,21 @@ func init() { | |||
} | |||
} | |||
|
|||
func ProvideDBConnectionString() string { |
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.
要不试试viper来读取配置?OS的方式有点费劲啊
Summary by CodeRabbit
New Features
Documentation