diff --git a/backend/src/api/handlers/handlers.go b/backend/src/api/handlers/handlers.go index 94e83fe2..86ed5c3e 100644 --- a/backend/src/api/handlers/handlers.go +++ b/backend/src/api/handlers/handlers.go @@ -11,6 +11,7 @@ import ( handlermodels "github.com/joshtyf/flowforge/src/api/handlers/models" "github.com/joshtyf/flowforge/src/database" "github.com/joshtyf/flowforge/src/database/client" + "github.com/joshtyf/flowforge/src/database/models" dbmodels "github.com/joshtyf/flowforge/src/database/models" "github.com/joshtyf/flowforge/src/events" "github.com/joshtyf/flowforge/src/logger" @@ -33,14 +34,17 @@ func HealthCheck(w http.ResponseWriter, r *http.Request) { func GetAllServiceRequest(w http.ResponseWriter, r *http.Request) { client, err := client.GetMongoClient() if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusInternalServerError) + logger.Error("[GetAllServiceRequest] Unable to get mongo client", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) return } allsr, err := database.NewServiceRequest(client).GetAll() if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusInternalServerError) + logger.Error("[GetAllServiceRequest] Error retrieving all service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) return } + logger.Info("[GetAllServiceRequest] Successfully retrieved service requests", map[string]interface{}{"count": len(allsr)}) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(allsr) w.WriteHeader(http.StatusOK) @@ -49,7 +53,8 @@ func GetAllServiceRequest(w http.ResponseWriter, r *http.Request) { func GetServiceRequest(w http.ResponseWriter, r *http.Request) { client, err := client.GetMongoClient() if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusInternalServerError) + logger.Error("[GetServiceRequest] Unable to get mongo client", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) return } vars := mux.Vars(r) @@ -57,9 +62,11 @@ func GetServiceRequest(w http.ResponseWriter, r *http.Request) { sr, err := database.NewServiceRequest(client).GetById(requestId) w.Header().Set("Content-Type", "application/json") if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusBadRequest) + logger.Error("[GetServiceRequest] Unable to retrieve service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusBadRequest) return } + logger.Info("[GetServiceRequest] Successfully retrieved service request", map[string]interface{}{"sr": sr}) json.NewEncoder(w).Encode(sr) w.WriteHeader(http.StatusOK) return @@ -68,7 +75,8 @@ func GetServiceRequest(w http.ResponseWriter, r *http.Request) { func CreateServiceRequest(w http.ResponseWriter, r *http.Request) { client, err := client.GetMongoClient() if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusInternalServerError) + logger.Error("[CreateServiceRequest] Unable to get mongo client", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) return } srm := &dbmodels.ServiceRequestModel{ @@ -79,21 +87,108 @@ func CreateServiceRequest(w http.ResponseWriter, r *http.Request) { err = json.NewDecoder(r.Body).Decode(srm) w.Header().Set("Content-Type", "application/json") if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusBadRequest) + logger.Error("[CreateServiceRequest] Unable to parse json request body", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("unable to parse json request body")), http.StatusBadRequest) return } res, err := database.NewServiceRequest(client).Create(srm) if err != nil { - JSONError(w, handlermodels.NewHttpError(err), http.StatusInternalServerError) + logger.Error("[CreateServiceRequest] Error creating service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) return } insertedId, _ := res.InsertedID.(primitive.ObjectID) srm.Id = insertedId + logger.Info("[CreateServiceRequest] Successfully created service request", map[string]interface{}{"sr": srm}) event.FireAsync(events.NewNewServiceRequestEvent(srm)) w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(srm) } +func CancelStartedServiceRequest(w http.ResponseWriter, r *http.Request) { + client, err := client.GetMongoClient() + if err != nil { + logger.Error("[CancelStartedServiceRequest] Unable to get mongo client", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + vars := mux.Vars(r) + requestId := vars["requestId"] + sr, err := database.NewServiceRequest(client).GetById(requestId) + if err != nil { + logger.Error("[CancelStartedServiceRequest] Error getting service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + status := sr.Status + w.Header().Set("Content-Type", "application/json") + if status != models.Pending && status != models.Running { + logger.Error("[CancelStartedServiceRequest] Unable to cancel service request as execution has been completed", nil) + JSONError(w, handlermodels.NewHttpError(errors.New("service request execution has been completed")), http.StatusBadRequest) + return + } + + if status == models.NotStarted { + logger.Error("[CancelStartedServiceRequest] Unable to cancel service request as execution has not been started", nil) + JSONError(w, handlermodels.NewHttpError(errors.New("service request execution has not been started")), http.StatusBadRequest) + return + } + + // TODO: implement cancellation of sr + + err = database.NewServiceRequest(client).UpdateStatus(requestId, models.Canceled) + + // TODO: discuss how to handle this error + if err != nil { + logger.Error("[CancelStartedServiceRequest] Unable to update service request status", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + + logger.Info("[CancelStartedServiceRequest] Successfully canceled started service request", nil) + w.WriteHeader(http.StatusOK) + return +} + +func UpdateServiceRequest(w http.ResponseWriter, r *http.Request) { + client, err := client.GetMongoClient() + if err != nil { + logger.Error("[UpdateServiceRequest] Unable to get mongo client", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + srm := &dbmodels.ServiceRequestModel{} + err = json.NewDecoder(r.Body).Decode(srm) + w.Header().Set("Content-Type", "application/json") + if err != nil { + logger.Error("[UpdateServiceRequest] Unable to parse json request body", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("unable to parse json request body")), http.StatusBadRequest) + return + } + vars := mux.Vars(r) + requestId := vars["requestId"] + sr, err := database.NewServiceRequest(client).GetById(requestId) + if err != nil { + logger.Error("[UpdateServiceRequest] Error getting service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + status := sr.Status + if status != models.NotStarted { + logger.Error("[UpdateServiceRequest] Unable to update service request as service request has been started", nil) + JSONError(w, handlermodels.NewHttpError(errors.New("service request has been started")), http.StatusBadRequest) + return + } + res, err := database.NewServiceRequest(client).UpdateById(requestId, srm) + if err != nil { + logger.Error("[UpdateServiceRequest] Error updating service request", map[string]interface{}{"err": err}) + JSONError(w, handlermodels.NewHttpError(errors.New("internal server error")), http.StatusInternalServerError) + return + } + logger.Info("[UpdateServiceRequest] Successfully updated service request", map[string]interface{}{"count": res.ModifiedCount}) + w.WriteHeader(http.StatusOK) +} + func CreatePipeline(w http.ResponseWriter, r *http.Request) { pipeline := &dbmodels.PipelineModel{ CreatedOn: time.Now(), @@ -103,6 +198,7 @@ func CreatePipeline(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error("[CreatePipeline] Unable to parse json request body", map[string]interface{}{"err": err}) JSONError(w, handlermodels.NewHttpError(errors.New("unable to parse json request body")), http.StatusBadRequest) + return } client, err := client.GetMongoClient() if err != nil { diff --git a/backend/src/database/models/service_request.go b/backend/src/database/models/service_request.go index 5652822c..fd782c3f 100644 --- a/backend/src/database/models/service_request.go +++ b/backend/src/database/models/service_request.go @@ -9,10 +9,12 @@ import ( type ServiceRequestStatus string const ( - Pending ServiceRequestStatus = "Pending" - Running ServiceRequestStatus = "Running" - Success ServiceRequestStatus = "Success" - Failure ServiceRequestStatus = "Failure" + Pending ServiceRequestStatus = "Pending" + Running ServiceRequestStatus = "Running" + Success ServiceRequestStatus = "Success" + Failure ServiceRequestStatus = "Failure" + Canceled ServiceRequestStatus = "Canceled" + NotStarted ServiceRequestStatus = "Not Started" ) type ServiceRequestModel struct { diff --git a/backend/src/database/service_request.go b/backend/src/database/service_request.go index 3d917136..d1ecaa19 100644 --- a/backend/src/database/service_request.go +++ b/backend/src/database/service_request.go @@ -33,6 +33,25 @@ func (sr *ServiceRequest) GetById(id string) (*models.ServiceRequestModel, error return srm, nil } +func (sr *ServiceRequest) UpdateById(id string, srm *models.ServiceRequestModel) (*mongo.UpdateResult, error) { + // TODO: update the method once form data is finalised + // objectId, _ := primitive.ObjectIDFromHex(id) + // filter := bson.M{"_id": objectId} + // update := bson.M{"$set": bson.M{ + // "pipeline_id": srm.PipelineId, + // "pipeline_version": srm.PipelineVersion, + // "last_updated": srm.LastUpdated, + // "remarks": srm.Remarks}} + + // res, err := sr.c.Database(DatabaseName).Collection("service_requests").UpdateOne(context.Background(), filter, update) + // if err != nil { + // return nil, err + // } + // return res, nil + + return nil, nil +} + func (sr *ServiceRequest) GetAll() ([]*models.ServiceRequestModel, error) { result, err := sr.c.Database(DatabaseName).Collection("service_requests").Find(context.Background(), bson.M{}) if err != nil { @@ -55,4 +74,4 @@ func (sr *ServiceRequest) UpdateStatus(id string, status models.ServiceRequestSt _, err = sr.c.Database(DatabaseName).Collection("service_requests").UpdateOne( context.Background(), bson.M{"_id": objectId}, bson.M{"$set": bson.M{"status": status}}) return err -} +} \ No newline at end of file diff --git a/backend/src/main.go b/backend/src/main.go index 87d70777..8c64eaab 100644 --- a/backend/src/main.go +++ b/backend/src/main.go @@ -21,6 +21,8 @@ func main() { r.HandleFunc("/api/service_request/{requestId}", handlers.GetServiceRequest).Methods("GET") r.HandleFunc("/api/service_request", handlers.GetAllServiceRequest).Methods("GET") r.HandleFunc("/api/service_request/{requestId}/approve", handlers.ApproveServiceRequest).Methods("POST").Headers("Content-Type", "application/json") + r.HandleFunc("/api/service_request/{requestId}/cancel", handlers.CancelStartedServiceRequest).Methods("GET") + r.HandleFunc("/api/service_request/{requestId}", handlers.UpdateServiceRequest).Methods("PATCH").Headers("Content-Type", "application/json") r.HandleFunc("/api/pipeline", handlers.CreatePipeline).Methods("POST").Headers("Content-Type", "application/json") r.HandleFunc("/api/pipeline", handlers.GetAllPipelines).Methods("GET") r.HandleFunc("/api/pipeline/{pipelineId}", handlers.GetPipeline).Methods("GET")