Reservation hook#21
Conversation
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds Discord notification support for reservation create/cancel/delete flows, wires a DiscordService through main/routes/handler, adds ReservationRepository.GetItemName and refactors SearchItemsAndCategories, and extends DiscordService with SendReservationCreated/SendReservationCancelled and embed thumbnail support. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant API as Fiber App/Routes
participant H as ReservationHandler
participant Repo as ReservationRepository
participant DB as SQL DB
participant D as DiscordService
Note over API,H: Reservation Creation Flow
User->>API: POST /reservations
API->>H: CreateReservation(req)
H->>DB: INSERT reservation
DB-->>H: reservation (id,itemID,user,dates)
alt DiscordService provided
H->>Repo: GetItemName(itemID)
Repo->>DB: SELECT name FROM items WHERE id=?
DB-->>Repo: name / no-row / error
Repo-->>H: itemName or error
H->>D: SendReservationCreated(itemName, start, end, isSlot, user)
D-->>H: ack/error
else No DiscordService
Note over H: Skip notification
end
H-->>API: 201 Created
API-->>User: Response
sequenceDiagram
autonumber
actor User
participant API as Fiber App/Routes
participant H as ReservationHandler
participant Repo as ReservationRepository
participant DB as SQL DB
participant D as DiscordService
Note over API,H: Reservation Cancel/Delete Flow
User->>API: DELETE /reservations/:id or PATCH end
API->>H: End/DeleteReservation(id)
H->>DB: UPDATE/DELETE reservation
DB-->>H: result (itemID, userToken/userID, dates)
alt DiscordService provided
H->>Repo: GetItemName(itemID)
Repo->>DB: SELECT name FROM items WHERE id=?
DB-->>Repo: name / error
Repo-->>H: itemName or error
H->>DB: SELECT user details if needed
DB-->>H: user info or defaults
H->>D: SendReservationCancelled(itemName, start, end, isSlot, user)
D-->>H: ack/error
else No DiscordService
Note over H: Skip notification
end
H-->>API: 200 OK
API-->>User: Response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull Request Overview
This PR adds Discord webhook notifications for reservation lifecycle events (creation, ending, deletion). A dedicated reservation webhook URL can be configured via DISCORD_RESERVATION_ALERT_WEBHOOK environment variable, falling back to the default Discord webhook if not set. Notifications include item details, reservation type (slot-based or open-ended), dates, and user information with optional profile pictures.
Key Changes:
- Added Discord notification methods for reservation created and cancelled events
- Integrated Discord service into reservation routes and handlers
- Added repository method to fetch item names for notifications
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| services/discord.go | Added new embed types (thumbnail, image) and notification methods for reservation events |
| routes/reservation.go | Updated route setup to accept and pass Discord service to reservation handler |
| main.go | Initialized separate Discord service for reservation notifications with dedicated webhook URL |
| handlers/reservation/reservation_handler.go | Integrated Discord notifications into reservation lifecycle (create, end, delete) with nil checks |
| handlers/reservation/repository/reservation_repository.go | Added GetItemName method to retrieve item names for notification purposes |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
main.go (1)
85-86: Avoid noisy warnings when no webhook: construct service only if URL is setCurrently a DiscordService is always created; if envs are empty, sends will fail and log warnings. Build the service only when an effective URL exists, pass nil otherwise.
Apply this diff:
- // Discord reservation-specific webhook (falls back to default if unset) - reservationDiscordService := services.NewDiscordService(os.Getenv("DISCORD_RESERVATION_ALERT_WEBHOOK")) + // Discord reservation-specific webhook (falls back to default if unset) + reservationWebhookURL := os.Getenv("DISCORD_RESERVATION_ALERT_WEBHOOK") + if reservationWebhookURL == "" { + reservationWebhookURL = os.Getenv("DISCORD_WEBHOOK_URL") + } + var reservationDiscordService *services.DiscordService + if reservationWebhookURL != "" { + reservationDiscordService = services.NewDiscordService(reservationWebhookURL) + }Also applies to: 173-173
services/discord.go (2)
125-155: Deduplicate common embed constructionBoth methods repeat slot type selection and field assembly. Extract a small helper to build reservation embeds and pass title/color.
Also applies to: 157-187
134-139: Confirm policy: sending full user emails to DiscordEmbeds include the user Email field. If Discord is considered a third party, this may be a privacy/compliance concern. Consider masking emails (e.g., jo****@Domain) or removing them if not strictly needed.
If masking is desired, add a helper and use it in both methods:
// Add near `safe`: func maskEmail(email string) string { if email == "" { return "" } at := strings.LastIndex(email, "@") if at <= 1 { return "***" } local, domain := email[:at], email[at+1:] if len(local) > 2 { local = local[:2] + strings.Repeat("*", len(local)-2) } else { local = strings.Repeat("*", len(local)) } return local + "@" + domain }Then replace the Email field values with:
safe(maskEmail(user.Email), "N/A").Note: you'll need to
import "strings".Also applies to: 166-171
handlers/reservation/reservation_handler.go (3)
447-463: Guard against empty webhook to avoid pointless send attemptsAdd a URL check to skip sending when the service exists but webhook URL is empty.
- if h.DiscordService != nil && res.User != nil { + if h.DiscordService != nil && h.DiscordService.WebhookURL != "" && res.User != nil {
481-494: Cancellation embed lacks start date—confirm intentYou send an empty startDate; embed will show N/A. If useful, consider fetching and including the original reservation start time.
709-739: Move user lookup to repository to keep handler thinDirect SQL in the handler breaks the layering established by ReservationRepository. Add a repository method (e.g., GetUserByEmail) and reuse here.
Example repository method:
// In handlers/reservation/repository/reservation_repository.go func (r *ReservationRepository) GetUserByEmail(email string) (models.ReservationUser, error) { var u models.ReservationUser row := r.DB.QueryRow("SELECT first_name, last_name, COALESCE(profile_picture,'') FROM newf WHERE email = $1", email) u.Email = email if err := row.Scan(&u.FirstName, &u.LastName, &u.ProfilePicture); err != nil { return u, err } return u, nil }Then replace the inline query with a call to
GetUserByEmail.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
handlers/reservation/repository/reservation_repository.go(1 hunks)handlers/reservation/reservation_handler.go(4 hunks)main.go(2 hunks)routes/reservation.go(1 hunks)services/discord.go(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
routes/reservation.go (2)
services/discord.go (1)
DiscordService(15-18)handlers/reservation/reservation_handler.go (1)
NewReservationHandler(21-26)
services/discord.go (1)
models/reservation.go (1)
ReservationUser(6-11)
handlers/reservation/reservation_handler.go (4)
handlers/reservation/repository/reservation_repository.go (2)
ReservationRepository(14-16)NewReservationRepository(18-22)services/discord.go (1)
DiscordService(15-18)utils/logManager.go (2)
LogMessage(62-64)LevelWarn(17-17)models/reservation.go (1)
ReservationUser(6-11)
handlers/reservation/repository/reservation_repository.go (1)
utils/logManager.go (3)
LogMessage(62-64)LevelWarn(17-17)LevelError(16-16)
main.go (2)
services/discord.go (1)
NewDiscordService(20-28)routes/reservation.go (1)
SetupReservationRoutes(12-35)
🔇 Additional comments (3)
routes/reservation.go (1)
9-10: Wiring looks goodSignature/import updates correctly inject DiscordService into the handler. Matches main.go.
Also applies to: 12-15
handlers/reservation/repository/reservation_repository.go (1)
741-754: GetItemName implementation is correctQuery, error handling, and logging are appropriate.
handlers/reservation/reservation_handler.go (1)
21-26: Constructor wiring is correctHandler now cleanly receives DiscordService via DI.
Summary by CodeRabbit