Skip to content

Commit

Permalink
Merge pull request #1995 from aliraza556/feature-ticket-review-webhook
Browse files Browse the repository at this point in the history
Add Webhook Endpoint and `ProcessTicketReview` Handler for Stackwork Ticket Review Automation
  • Loading branch information
elraphty authored Nov 28, 2024
2 parents 084dd14 + 1fa7fbc commit bd9e1fc
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 11 deletions.
60 changes: 49 additions & 11 deletions handlers/ticket.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"

"github.com/go-chi/chi"
"github.com/google/uuid"
"github.com/stakwork/sphinx-tribes/db"
"github.com/stakwork/sphinx-tribes/utils"
)

type ticketHandler struct {
Expand Down Expand Up @@ -45,7 +47,7 @@ func (th *ticketHandler) GetTicket(w http.ResponseWriter, r *http.Request) {
return
}

respondWithJSON(w, http.StatusOK, ticket)
utils.RespondWithJSON(w, http.StatusOK, ticket)
}

func (th *ticketHandler) UpdateTicket(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -85,7 +87,7 @@ func (th *ticketHandler) UpdateTicket(w http.ResponseWriter, r *http.Request) {
return
}

respondWithJSON(w, http.StatusOK, updatedTicket)
utils.RespondWithJSON(w, http.StatusOK, updatedTicket)
}

func (th *ticketHandler) DeleteTicket(w http.ResponseWriter, r *http.Request) {
Expand All @@ -105,13 +107,13 @@ func (th *ticketHandler) DeleteTicket(w http.ResponseWriter, r *http.Request) {
return
}

respondWithJSON(w, http.StatusOK, map[string]string{"status": "success"})
utils.RespondWithJSON(w, http.StatusOK, map[string]string{"status": "success"})
}

func (th *ticketHandler) PostTicketDataToStakwork(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
respondWithJSON(w, http.StatusBadRequest, TicketResponse{
utils.RespondWithJSON(w, http.StatusBadRequest, TicketResponse{
Success: false,
Message: "Validation failed",
Errors: []string{"Error reading request body"},
Expand All @@ -121,7 +123,7 @@ func (th *ticketHandler) PostTicketDataToStakwork(w http.ResponseWriter, r *http

var ticket db.Tickets
if err := json.Unmarshal(body, &ticket); err != nil {
respondWithJSON(w, http.StatusBadRequest, TicketResponse{
utils.RespondWithJSON(w, http.StatusBadRequest, TicketResponse{
Success: false,
Message: "Validation failed",
Errors: []string{"Error parsing request body: " + err.Error()},
Expand Down Expand Up @@ -149,23 +151,59 @@ func (th *ticketHandler) PostTicketDataToStakwork(w http.ResponseWriter, r *http
}

if len(validationErrors) > 0 {
respondWithJSON(w, http.StatusBadRequest, TicketResponse{
utils.RespondWithJSON(w, http.StatusBadRequest, TicketResponse{
Success: false,
Message: "Validation failed",
Errors: validationErrors,
})
return
}

respondWithJSON(w, http.StatusOK, TicketResponse{
utils.RespondWithJSON(w, http.StatusOK, TicketResponse{
Success: true,
TicketID: ticket.UUID.String(),
Message: "Ticket submission is valid",
})
}

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(payload)
func (th *ticketHandler) ProcessTicketReview(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading request body: %v", err)
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}

var reviewReq utils.TicketReviewRequest
if err := json.Unmarshal(body, &reviewReq); err != nil {
log.Printf("Error parsing request JSON: %v", err)
http.Error(w, "Error parsing request body", http.StatusBadRequest)
return
}

if err := utils.ValidateTicketReviewRequest(&reviewReq); err != nil {
log.Printf("Invalid request data: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

ticket, err := th.db.GetTicket(reviewReq.TicketUUID)
if err != nil {
log.Printf("Error fetching ticket: %v", err)
http.Error(w, "Ticket not found", http.StatusNotFound)
return
}

ticket.Description = reviewReq.TicketDescription

updatedTicket, err := th.db.UpdateTicket(ticket)
if err != nil {
log.Printf("Error updating ticket: %v", err)
http.Error(w, "Failed to update ticket", http.StatusInternalServerError)
return
}

log.Printf("Successfully updated ticket %s", reviewReq.TicketUUID)

utils.RespondWithJSON(w, http.StatusOK, updatedTicket)
}
1 change: 1 addition & 0 deletions routes/ticket_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TicketRoutes() chi.Router {
r.Get("/{uuid}", ticketHandler.GetTicket)
r.Put("/{uuid}", ticketHandler.UpdateTicket)
r.Delete("/{uuid}", ticketHandler.DeleteTicket)
r.Post("/review", ticketHandler.ProcessTicketReview)
})

return r
Expand Down
36 changes: 36 additions & 0 deletions utils/ticket_processor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package utils

import (
"encoding/json"
"errors"
"net/http"
)

type TicketReviewRequest struct {
FeatureUUID string `json:"featureUUID" validate:"required"`
PhaseUUID string `json:"phaseUUID" validate:"required"`
TicketUUID string `json:"ticketUUID" validate:"required"`
TicketDescription string `json:"ticketDescription" validate:"required"`
}

func ValidateTicketReviewRequest(req *TicketReviewRequest) error {
if req.FeatureUUID == "" {
return errors.New("featureUUID is required")
}
if req.PhaseUUID == "" {
return errors.New("phaseUUID is required")
}
if req.TicketUUID == "" {
return errors.New("ticketUUID is required")
}
if req.TicketDescription == "" {
return errors.New("ticketDescription is required")
}
return nil
}

func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(payload)
}

0 comments on commit bd9e1fc

Please sign in to comment.