From dd3ebd6a9efd66883c43a2a15b0bebe2fc6c06c8 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 20 Nov 2025 19:41:30 -0500 Subject: [PATCH 01/14] Completed Upload misc. files and associate them with MCAPS --- cloud_webserver_v2/docker-compose.yml | 2 +- .../database/usecase/vehicle_run_usecase.go | 20 +++++++++ .../internal/delivery/http/mcap_handler.go | 45 +++++++++++++++++++ .../internal/models/vehicle_run_model.go | 7 +++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/cloud_webserver_v2/docker-compose.yml b/cloud_webserver_v2/docker-compose.yml index 6b4b71e..1fc22af 100644 --- a/cloud_webserver_v2/docker-compose.yml +++ b/cloud_webserver_v2/docker-compose.yml @@ -17,4 +17,4 @@ services: volumes: run_metadata: matlab_mps_data: - external: true + diff --git a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go index 58cdf89..33581f4 100644 --- a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go @@ -116,3 +116,23 @@ func (uc *VehicleRunUseCase) DeleteVehicleRunById(ctx context.Context, id primit func (uc *VehicleRunUseCase) UpdateVehicleRun(ctx context.Context, id primitive.ObjectID, model *models.VehicleRunModel) error { return uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, id, model) } + +func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primitive.ObjectID, awsBucket string, fileName string, filePath string) (*models.VehicleRunModel, error) { + vehicleRun, err := uc.vechicleRunRepo.GetVehicleRunFromId(ctx, vehicleRunID) + if err != nil { + return nil, err + } + miscFile := models.FileModel{ + AwsBucket: awsBucket, + FilePath: filePath, + FileName: fileName, + } + vehicleRun.MiscFiles = append(vehicleRun.MiscFiles, miscFile) + err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) + if err != nil { + return nil, err + } + return vehicleRun, nil +} + + diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index cfe8184..d57fb30 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -1,6 +1,7 @@ package http import ( + "context" "fmt" "log" "net/http" @@ -62,9 +63,53 @@ func NewMcapHandler( r.Get("/{id}/process", HandlerFunc(handler.ProcessMatlabJob).ServeHTTP) r.Post("/{id}/updateMetadataRecords", HandlerFunc(handler.UpdateMetadataRecordFromID).ServeHTTP) r.Delete("/{id}/resetMetaDataRecord/{metadata}", HandlerFunc(handler.ResetMetadataRecordFromID).ServeHTTP) + r.Post("/{id}/addMiscFiles", handler.UploadNewMiscFile) }) } +// Retrieves misc files uploaded from request, calls S3 usecase to update S3, & calls vehicle run usecase to +// update MongoDB +func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) { + err := r.ParseMultipartForm(32 << 20) + if err != nil { + http.Error(w, "Failed to parse multipart form", http.StatusBadRequest) + return + } + file, header, err := r.FormFile("file") + if err != nil { + http.Error(w, "Could not read file from request", http.StatusBadRequest) + return + } + defer file.Close() + + idStr := chi.URLParam(r, "id") + vehicleRunID, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + http.Error(w, "Invalid vehicle run ID", http.StatusBadRequest) + return + } + + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) + defer cancel() + s3Key := fmt.Sprintf("%s/%s", vehicleRunID.Hex(), header.Filename) + err = h.s3Repository.WriteObjectReader(ctx, file, s3Key) + if err != nil { + http.Error(w, "Failed to upload to S3: "+err.Error(), http.StatusInternalServerError) + return + } + + vehicleRun, err := h.dbClient.VehicleRunUseCase().AddMiscFile(ctx, vehicleRunID, h.s3Repository.Bucket(), header.Filename, s3Key) + if err != nil { + http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) + return + } + response := map[string]interface{}{ + "message": "Misc file uploaded successfully", + "data": vehicleRun, + } + render.JSON(w, r, response) +} + // GetMcapsFromFilters takes in filters through Query parameters and will respond with a // map with a message and data field where data contains the filtered MCAPs func (h *mcapHandler) GetMcapsFromFilters(w http.ResponseWriter, r *http.Request) { diff --git a/cloud_webserver_v2/internal/models/vehicle_run_model.go b/cloud_webserver_v2/internal/models/vehicle_run_model.go index 878258c..a455544 100644 --- a/cloud_webserver_v2/internal/models/vehicle_run_model.go +++ b/cloud_webserver_v2/internal/models/vehicle_run_model.go @@ -59,6 +59,7 @@ type VehicleRunModel struct { Date time.Time `bson:"date"` MatFiles []FileModel `bson:"mat_files,omitempty"` MpsRecord MpsRecordModel `bson:"mps_record,omitempty"` + MiscFiles []FileModel `bson:"misc_files,omitempty"` } type VehicleRunModelResponse struct { @@ -74,6 +75,8 @@ type VehicleRunModelResponse struct { EventType *string `json:"event_type"` DynamicFields map[string]interface{} `json:"dynamic_fields"` MpsRecord MpsRecordModel `json:"mps_record"` + MiscFiles []FileModelResponse `json:"misc_files"` + } func VehicleRunSerialize(ctx context.Context, s3Repo *s3.S3Repository, model VehicleRunModel) VehicleRunModelResponse { @@ -107,6 +110,10 @@ func VehicleRunSerialize(ctx context.Context, s3Repo *s3.S3Repository, model Veh modelOut.ContentFiles[key] = fileResponses } } + if model.MiscFiles != nil && len(model.MiscFiles) > 0 { + miscResponses := getFileModelResponse(ctx, s3Repo, model.MiscFiles) + modelOut.MiscFiles = miscResponses + } return modelOut } From a1ece81d5dec65782d6ca5a52a5d0ef94972f8f4 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 20 Nov 2025 19:46:28 -0500 Subject: [PATCH 02/14] Put external back in --- cloud_webserver_v2/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/cloud_webserver_v2/docker-compose.yml b/cloud_webserver_v2/docker-compose.yml index 1fc22af..64b2078 100644 --- a/cloud_webserver_v2/docker-compose.yml +++ b/cloud_webserver_v2/docker-compose.yml @@ -17,4 +17,5 @@ services: volumes: run_metadata: matlab_mps_data: + external: true From 3d21b1dad1ed9cbcedc68392db22e93f6953666c Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 20 Nov 2025 19:49:27 -0500 Subject: [PATCH 03/14] Fix --- cloud_webserver_v2/docker-compose.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cloud_webserver_v2/docker-compose.yml b/cloud_webserver_v2/docker-compose.yml index 64b2078..ea5e2bc 100644 --- a/cloud_webserver_v2/docker-compose.yml +++ b/cloud_webserver_v2/docker-compose.yml @@ -17,5 +17,4 @@ services: volumes: run_metadata: matlab_mps_data: - external: true - + external: true \ No newline at end of file From f8eb14e991353c2823c8b0726f4bcc50dbd47127 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 20 Nov 2025 19:56:52 -0500 Subject: [PATCH 04/14] format files --- .../database/usecase/vehicle_run_usecase.go | 22 ++++---- .../internal/delivery/http/mcap_handler.go | 56 +++++++++---------- .../internal/models/vehicle_run_model.go | 5 +- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go index 33581f4..6e8866d 100644 --- a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go @@ -118,21 +118,19 @@ func (uc *VehicleRunUseCase) UpdateVehicleRun(ctx context.Context, id primitive. } func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primitive.ObjectID, awsBucket string, fileName string, filePath string) (*models.VehicleRunModel, error) { - vehicleRun, err := uc.vechicleRunRepo.GetVehicleRunFromId(ctx, vehicleRunID) - if err != nil { - return nil, err - } + vehicleRun, err := uc.vechicleRunRepo.GetVehicleRunFromId(ctx, vehicleRunID) + if err != nil { + return nil, err + } miscFile := models.FileModel{ AwsBucket: awsBucket, FilePath: filePath, FileName: fileName, } - vehicleRun.MiscFiles = append(vehicleRun.MiscFiles, miscFile) - err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) - if err != nil { - return nil, err - } - return vehicleRun, nil + vehicleRun.MiscFiles = append(vehicleRun.MiscFiles, miscFile) + err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) + if err != nil { + return nil, err + } + return vehicleRun, nil } - - diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index d57fb30..649e0bf 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -67,31 +67,31 @@ func NewMcapHandler( }) } -// Retrieves misc files uploaded from request, calls S3 usecase to update S3, & calls vehicle run usecase to +// Retrieves misc files uploaded from request, calls S3 usecase to update S3, & calls vehicle run usecase to // update MongoDB func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) { - err := r.ParseMultipartForm(32 << 20) - if err != nil { - http.Error(w, "Failed to parse multipart form", http.StatusBadRequest) - return - } + err := r.ParseMultipartForm(32 << 20) + if err != nil { + http.Error(w, "Failed to parse multipart form", http.StatusBadRequest) + return + } file, header, err := r.FormFile("file") - if err != nil { - http.Error(w, "Could not read file from request", http.StatusBadRequest) - return - } - defer file.Close() - + if err != nil { + http.Error(w, "Could not read file from request", http.StatusBadRequest) + return + } + defer file.Close() + idStr := chi.URLParam(r, "id") - vehicleRunID, err := primitive.ObjectIDFromHex(idStr) - if err != nil { - http.Error(w, "Invalid vehicle run ID", http.StatusBadRequest) - return - } - - ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) + vehicleRunID, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + http.Error(w, "Invalid vehicle run ID", http.StatusBadRequest) + return + } + + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() - s3Key := fmt.Sprintf("%s/%s", vehicleRunID.Hex(), header.Filename) + s3Key := fmt.Sprintf("%s/%s", vehicleRunID.Hex(), header.Filename) err = h.s3Repository.WriteObjectReader(ctx, file, s3Key) if err != nil { http.Error(w, "Failed to upload to S3: "+err.Error(), http.StatusInternalServerError) @@ -99,15 +99,15 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) } vehicleRun, err := h.dbClient.VehicleRunUseCase().AddMiscFile(ctx, vehicleRunID, h.s3Repository.Bucket(), header.Filename, s3Key) - if err != nil { - http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) - return - } + if err != nil { + http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) + return + } response := map[string]interface{}{ - "message": "Misc file uploaded successfully", - "data": vehicleRun, - } - render.JSON(w, r, response) + "message": "Misc file uploaded successfully", + "data": vehicleRun, + } + render.JSON(w, r, response) } // GetMcapsFromFilters takes in filters through Query parameters and will respond with a diff --git a/cloud_webserver_v2/internal/models/vehicle_run_model.go b/cloud_webserver_v2/internal/models/vehicle_run_model.go index a455544..a803529 100644 --- a/cloud_webserver_v2/internal/models/vehicle_run_model.go +++ b/cloud_webserver_v2/internal/models/vehicle_run_model.go @@ -59,7 +59,7 @@ type VehicleRunModel struct { Date time.Time `bson:"date"` MatFiles []FileModel `bson:"mat_files,omitempty"` MpsRecord MpsRecordModel `bson:"mps_record,omitempty"` - MiscFiles []FileModel `bson:"misc_files,omitempty"` + MiscFiles []FileModel `bson:"misc_files,omitempty"` } type VehicleRunModelResponse struct { @@ -75,8 +75,7 @@ type VehicleRunModelResponse struct { EventType *string `json:"event_type"` DynamicFields map[string]interface{} `json:"dynamic_fields"` MpsRecord MpsRecordModel `json:"mps_record"` - MiscFiles []FileModelResponse `json:"misc_files"` - + MiscFiles []FileModelResponse `json:"misc_files"` } func VehicleRunSerialize(ctx context.Context, s3Repo *s3.S3Repository, model VehicleRunModel) VehicleRunModelResponse { From a497879e4839c09725552df97ce197d56cc174f9 Mon Sep 17 00:00:00 2001 From: Ryan Lau <47727459+ryanlau@users.noreply.github.com> Date: Sat, 22 Nov 2025 11:35:46 -0500 Subject: [PATCH 05/14] undo docker compose changes --- cloud_webserver_v2/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud_webserver_v2/docker-compose.yml b/cloud_webserver_v2/docker-compose.yml index ea5e2bc..6b4b71e 100644 --- a/cloud_webserver_v2/docker-compose.yml +++ b/cloud_webserver_v2/docker-compose.yml @@ -17,4 +17,4 @@ services: volumes: run_metadata: matlab_mps_data: - external: true \ No newline at end of file + external: true From da87e68b6e639d101a31297ebd71343d7ce19aee Mon Sep 17 00:00:00 2001 From: janista-ng Date: Sun, 18 Jan 2026 16:41:35 -0500 Subject: [PATCH 06/14] Changes MiscFiles to ContentFiles --- .../internal/database/usecase/vehicle_run_usecase.go | 5 ++++- cloud_webserver_v2/internal/models/vehicle_run_model.go | 6 ------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go index 6e8866d..7fb1a76 100644 --- a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go @@ -127,7 +127,10 @@ func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primi FilePath: filePath, FileName: fileName, } - vehicleRun.MiscFiles = append(vehicleRun.MiscFiles, miscFile) + if vehicleRun.ContentFiles["misc_files"] == nil { + vehicleRun.ContentFiles["misc_files"] = []models.FileModel{} + } + vehicleRun.ContentFiles["misc_files"] = append(vehicleRun.ContentFiles["misc_files"], miscFile) err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) if err != nil { return nil, err diff --git a/cloud_webserver_v2/internal/models/vehicle_run_model.go b/cloud_webserver_v2/internal/models/vehicle_run_model.go index a803529..878258c 100644 --- a/cloud_webserver_v2/internal/models/vehicle_run_model.go +++ b/cloud_webserver_v2/internal/models/vehicle_run_model.go @@ -59,7 +59,6 @@ type VehicleRunModel struct { Date time.Time `bson:"date"` MatFiles []FileModel `bson:"mat_files,omitempty"` MpsRecord MpsRecordModel `bson:"mps_record,omitempty"` - MiscFiles []FileModel `bson:"misc_files,omitempty"` } type VehicleRunModelResponse struct { @@ -75,7 +74,6 @@ type VehicleRunModelResponse struct { EventType *string `json:"event_type"` DynamicFields map[string]interface{} `json:"dynamic_fields"` MpsRecord MpsRecordModel `json:"mps_record"` - MiscFiles []FileModelResponse `json:"misc_files"` } func VehicleRunSerialize(ctx context.Context, s3Repo *s3.S3Repository, model VehicleRunModel) VehicleRunModelResponse { @@ -109,10 +107,6 @@ func VehicleRunSerialize(ctx context.Context, s3Repo *s3.S3Repository, model Veh modelOut.ContentFiles[key] = fileResponses } } - if model.MiscFiles != nil && len(model.MiscFiles) > 0 { - miscResponses := getFileModelResponse(ctx, s3Repo, model.MiscFiles) - modelOut.MiscFiles = miscResponses - } return modelOut } From 674867a7c6ad9576ef20e015ec4754dff18bfdbb Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 28 Jan 2026 19:46:28 -0500 Subject: [PATCH 07/14] resolved fixes --- .../database/usecase/vehicle_run_usecase.go | 17 ++++++++++++++++- .../internal/delivery/http/mcap_handler.go | 13 ++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go index 7fb1a76..11b06b2 100644 --- a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go @@ -129,7 +129,7 @@ func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primi } if vehicleRun.ContentFiles["misc_files"] == nil { vehicleRun.ContentFiles["misc_files"] = []models.FileModel{} - } + } vehicleRun.ContentFiles["misc_files"] = append(vehicleRun.ContentFiles["misc_files"], miscFile) err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) if err != nil { @@ -137,3 +137,18 @@ func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primi } return vehicleRun, nil } + +func (uc *VehicleRunUseCase) FileNameExists(ctx context.Context, vehicleRunID primitive.ObjectID, fileName string) (bool, error) { + vehicleRun, err := uc.vechicleRunRepo.GetVehicleRunFromId(ctx, vehicleRunID) + if err != nil { + return true, err + } + if vehicleRun.ContentFiles["misc_files"] != nil { + for _, f := range vehicleRun.ContentFiles["misc_files"] { + if f.FileName == fileName { + return true, nil + } + } + } + return false, nil +} diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index 649e0bf..f13d2ae 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -91,21 +91,28 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() - s3Key := fmt.Sprintf("%s/%s", vehicleRunID.Hex(), header.Filename) + s3Key := fmt.Sprintf("%s/miscFiles/%s", vehicleRunID.Hex(), header.Filename) + exists, err := h.dbClient.VehicleRunUseCase().FileNameExists(ctx, vehicleRunID, header.Filename) + if (err != nil) { + http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) + } + if (exists) { + http.Error(w, "File name already exists, duplicate file names not allowed", http.StatusNotAcceptable) + return + } err = h.s3Repository.WriteObjectReader(ctx, file, s3Key) if err != nil { http.Error(w, "Failed to upload to S3: "+err.Error(), http.StatusInternalServerError) return } - vehicleRun, err := h.dbClient.VehicleRunUseCase().AddMiscFile(ctx, vehicleRunID, h.s3Repository.Bucket(), header.Filename, s3Key) + _, err = h.dbClient.VehicleRunUseCase().AddMiscFile(ctx, vehicleRunID, h.s3Repository.Bucket(), header.Filename, s3Key) if err != nil { http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) return } response := map[string]interface{}{ "message": "Misc file uploaded successfully", - "data": vehicleRun, } render.JSON(w, r, response) } From f5eef1a8c17bc492bb09cc470d33b49fc2e87e0a Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 28 Jan 2026 19:53:46 -0500 Subject: [PATCH 08/14] ran go format --- .../internal/database/usecase/vehicle_run_usecase.go | 2 +- cloud_webserver_v2/internal/delivery/http/mcap_handler.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go index 11b06b2..4a42c1a 100644 --- a/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/vehicle_run_usecase.go @@ -129,7 +129,7 @@ func (uc *VehicleRunUseCase) AddMiscFile(ctx context.Context, vehicleRunID primi } if vehicleRun.ContentFiles["misc_files"] == nil { vehicleRun.ContentFiles["misc_files"] = []models.FileModel{} - } + } vehicleRun.ContentFiles["misc_files"] = append(vehicleRun.ContentFiles["misc_files"], miscFile) err = uc.vechicleRunRepo.UpdateVehicleRunFromId(ctx, vehicleRunID, vehicleRun) if err != nil { diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index f13d2ae..e4fbef0 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -93,10 +93,10 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) defer cancel() s3Key := fmt.Sprintf("%s/miscFiles/%s", vehicleRunID.Hex(), header.Filename) exists, err := h.dbClient.VehicleRunUseCase().FileNameExists(ctx, vehicleRunID, header.Filename) - if (err != nil) { + if err != nil { http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) } - if (exists) { + if exists { http.Error(w, "File name already exists, duplicate file names not allowed", http.StatusNotAcceptable) return } From f006edd8736ce83846d9d84cd3c6253c3ee960e4 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 28 Jan 2026 19:57:51 -0500 Subject: [PATCH 09/14] removed context import --- cloud_webserver_v2/internal/delivery/http/mcap_handler.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index e4fbef0..c026a9c 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -1,7 +1,6 @@ package http import ( - "context" "fmt" "log" "net/http" @@ -70,6 +69,7 @@ func NewMcapHandler( // Retrieves misc files uploaded from request, calls S3 usecase to update S3, & calls vehicle run usecase to // update MongoDB func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() err := r.ParseMultipartForm(32 << 20) if err != nil { http.Error(w, "Failed to parse multipart form", http.StatusBadRequest) @@ -89,8 +89,6 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) return } - ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) - defer cancel() s3Key := fmt.Sprintf("%s/miscFiles/%s", vehicleRunID.Hex(), header.Filename) exists, err := h.dbClient.VehicleRunUseCase().FileNameExists(ctx, vehicleRunID, header.Filename) if err != nil { From f5e02c216bab072d5217a705ebc1073100d90ff6 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 4 Feb 2026 20:22:39 -0500 Subject: [PATCH 10/14] fixes 2/4 --- .../internal/delivery/http/mcap_handler.go | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index c026a9c..1ba8b63 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -62,57 +62,52 @@ func NewMcapHandler( r.Get("/{id}/process", HandlerFunc(handler.ProcessMatlabJob).ServeHTTP) r.Post("/{id}/updateMetadataRecords", HandlerFunc(handler.UpdateMetadataRecordFromID).ServeHTTP) r.Delete("/{id}/resetMetaDataRecord/{metadata}", HandlerFunc(handler.ResetMetadataRecordFromID).ServeHTTP) - r.Post("/{id}/addMiscFiles", handler.UploadNewMiscFile) + r.Post("/{id}/addMiscFile", HandlerFunc(handler.UploadNewMiscFile).ServeHTTP) }) } // Retrieves misc files uploaded from request, calls S3 usecase to update S3, & calls vehicle run usecase to // update MongoDB -func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) { +func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) *HandlerError { ctx := r.Context() err := r.ParseMultipartForm(32 << 20) if err != nil { - http.Error(w, "Failed to parse multipart form", http.StatusBadRequest) - return + return NewHandlerError(fmt.Sprintf("Failed to parse multipart form"), http.StatusBadRequest) } file, header, err := r.FormFile("file") if err != nil { - http.Error(w, "Could not read file from request", http.StatusBadRequest) - return + return NewHandlerError(fmt.Sprintf("Could not read file from request"), http.StatusBadRequest) } defer file.Close() idStr := chi.URLParam(r, "id") vehicleRunID, err := primitive.ObjectIDFromHex(idStr) if err != nil { - http.Error(w, "Invalid vehicle run ID", http.StatusBadRequest) - return + return NewHandlerError(fmt.Sprint("Invalid vehicle run ID"), http.StatusBadRequest) } s3Key := fmt.Sprintf("%s/miscFiles/%s", vehicleRunID.Hex(), header.Filename) exists, err := h.dbClient.VehicleRunUseCase().FileNameExists(ctx, vehicleRunID, header.Filename) if err != nil { - http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) + return NewHandlerError(fmt.Sprintf("Failed to save misc file to vehicle run: "+err.Error()), http.StatusInternalServerError) } if exists { - http.Error(w, "File name already exists, duplicate file names not allowed", http.StatusNotAcceptable) - return + return NewHandlerError(fmt.Sprintf("File name already exists, duplicate file names not allowed"), http.StatusNotAcceptable) } err = h.s3Repository.WriteObjectReader(ctx, file, s3Key) if err != nil { - http.Error(w, "Failed to upload to S3: "+err.Error(), http.StatusInternalServerError) - return + return NewHandlerError(fmt.Sprintf("Failed to upload to S3: "+err.Error()), http.StatusInternalServerError) } _, err = h.dbClient.VehicleRunUseCase().AddMiscFile(ctx, vehicleRunID, h.s3Repository.Bucket(), header.Filename, s3Key) if err != nil { - http.Error(w, "Failed to save misc file to vehicle run: "+err.Error(), http.StatusInternalServerError) - return + return NewHandlerError(fmt.Sprintf("Failed to save misc file to vehicle run: "+err.Error()), http.StatusInternalServerError) } response := map[string]interface{}{ "message": "Misc file uploaded successfully", } render.JSON(w, r, response) + return nil } // GetMcapsFromFilters takes in filters through Query parameters and will respond with a From f614d7858cc3f7faf5a480279cd6a9653363e469 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 4 Feb 2026 21:17:48 -0500 Subject: [PATCH 11/14] DeleteMiscFiles --- .../internal/delivery/http/mcap_handler.go | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index 1ba8b63..d1fa579 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -63,6 +63,7 @@ func NewMcapHandler( r.Post("/{id}/updateMetadataRecords", HandlerFunc(handler.UpdateMetadataRecordFromID).ServeHTTP) r.Delete("/{id}/resetMetaDataRecord/{metadata}", HandlerFunc(handler.ResetMetadataRecordFromID).ServeHTTP) r.Post("/{id}/addMiscFile", HandlerFunc(handler.UploadNewMiscFile).ServeHTTP) + r.Delete("{id}/miscFiles/{fileName}", HandlerFunc(handler.DeleteMiscFile).ServeHTTP) }) } @@ -72,11 +73,11 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) ctx := r.Context() err := r.ParseMultipartForm(32 << 20) if err != nil { - return NewHandlerError(fmt.Sprintf("Failed to parse multipart form"), http.StatusBadRequest) + return NewHandlerError(fmt.Sprintf("Failed to parse multipart form"), http.StatusBadRequest) } file, header, err := r.FormFile("file") if err != nil { - return NewHandlerError(fmt.Sprintf("Could not read file from request"), http.StatusBadRequest) + return NewHandlerError(fmt.Sprintf("Could not read file from request"), http.StatusBadRequest) } defer file.Close() @@ -110,6 +111,49 @@ func (h *mcapHandler) UploadNewMiscFile(w http.ResponseWriter, r *http.Request) return nil } +func (h *mcapHandler) DeleteMiscFile(w http.ResponseWriter, r *http.Request) *HandlerError { + ctx := r.Context() + id := chi.URLParam(r, "id") + vehicleRunID, err := primitive.ObjectIDFromHex(id) + if err != nil { + return NewHandlerError(fmt.Sprintf("Could not decode MCAP id %v, %v", id, err), http.StatusInternalServerError) + } + fileName := chi.URLParam(r, "fileName") + vehicleRun, err := h.dbClient.VehicleRunUseCase().GetVehicleRunById(ctx, vehicleRunID) + if err != nil { + if err.Error() == "mongo: no documents in result" { + return NewHandlerError(fmt.Sprintf("no run with id %v found", id), http.StatusNotFound) + } + return NewHandlerError(err.Error(), http.StatusInternalServerError) + } + var targetFile *models.FileModel + for _, f := range vehicleRun.ContentFiles["misc_files"] { + if f.FileName == fileName { + targetFile = &f + break + } + } + if targetFile == nil { + return NewHandlerError(fmt.Sprintf("File does not exist to be deleted"), http.StatusBadRequest) + } + err = h.s3Repository.DeleteObject(ctx, targetFile.AwsBucket, targetFile.FilePath) + if err != nil { + return NewHandlerError(err.Error(), http.StatusInternalServerError) + } + updatedFiles := make([]models.FileModel, 0) + for _, f := range vehicleRun.ContentFiles["misc_files"] { + if f.FileName != fileName { + updatedFiles = append(updatedFiles, f) + } + } + vehicleRun.ContentFiles["misc_files"] = updatedFiles + err = h.dbClient.VehicleRunUseCase().UpdateVehicleRun(ctx, vehicleRunID, vehicleRun) + if err != nil { + return NewHandlerError(fmt.Sprintf("Failed to update vehicle run"), http.StatusInternalServerError) + } + return nil +} + // GetMcapsFromFilters takes in filters through Query parameters and will respond with a // map with a message and data field where data contains the filtered MCAPs func (h *mcapHandler) GetMcapsFromFilters(w http.ResponseWriter, r *http.Request) { From 8fc331afadb57a000d93a7576bb3ea1e720261ab Mon Sep 17 00:00:00 2001 From: janista-ng Date: Wed, 4 Feb 2026 21:38:33 -0500 Subject: [PATCH 12/14] Fixes --- cloud_webserver_v2/internal/delivery/http/mcap_handler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go index d1fa579..36e06ba 100644 --- a/cloud_webserver_v2/internal/delivery/http/mcap_handler.go +++ b/cloud_webserver_v2/internal/delivery/http/mcap_handler.go @@ -63,7 +63,7 @@ func NewMcapHandler( r.Post("/{id}/updateMetadataRecords", HandlerFunc(handler.UpdateMetadataRecordFromID).ServeHTTP) r.Delete("/{id}/resetMetaDataRecord/{metadata}", HandlerFunc(handler.ResetMetadataRecordFromID).ServeHTTP) r.Post("/{id}/addMiscFile", HandlerFunc(handler.UploadNewMiscFile).ServeHTTP) - r.Delete("{id}/miscFiles/{fileName}", HandlerFunc(handler.DeleteMiscFile).ServeHTTP) + r.Delete("/{id}/deleteMiscFile/{fileName}", HandlerFunc(handler.DeleteMiscFile).ServeHTTP) }) } @@ -151,6 +151,10 @@ func (h *mcapHandler) DeleteMiscFile(w http.ResponseWriter, r *http.Request) *Ha if err != nil { return NewHandlerError(fmt.Sprintf("Failed to update vehicle run"), http.StatusInternalServerError) } + response := map[string]interface{}{ + "message": "Misc file deleted successfully", + } + render.JSON(w, r, response) return nil } From 3614438f880147014ce40754aceb29695c33b1ec Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 23 Apr 2026 18:41:42 -0400 Subject: [PATCH 13/14] events logging --- .../internal/background/mcap_jobs.go | 25 +++- .../internal/database/database.go | 11 ++ .../database/repository/events_repository.go | 109 ++++++++++++++++++ .../database/usecase/events_usecase.go | 91 +++++++++++++++ .../internal/models/events_filters_model.go | 16 +++ .../internal/models/events_model.go | 17 +++ 6 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 cloud_webserver_v2/internal/database/repository/events_repository.go create mode 100644 cloud_webserver_v2/internal/database/usecase/events_usecase.go create mode 100644 cloud_webserver_v2/internal/models/events_filters_model.go create mode 100644 cloud_webserver_v2/internal/models/events_model.go diff --git a/cloud_webserver_v2/internal/background/mcap_jobs.go b/cloud_webserver_v2/internal/background/mcap_jobs.go index a8c8eb0..b90383e 100644 --- a/cloud_webserver_v2/internal/background/mcap_jobs.go +++ b/cloud_webserver_v2/internal/background/mcap_jobs.go @@ -25,12 +25,16 @@ type PostProcessMCAPUploadJob struct{} // It also saves all this information to the database and stores files on S3. func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) error { ctx := context.TODO() + recordId := primitive.NewObjectID() fp.setCurrentlyProcessing(true) fp.updateJobStatus(job, StatusProcessing) + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "job_started", nil) genericFileName := strings.Split(job.Filename, ".")[0] mcapResults, err := p.readMCAPMessages(ctx, job, genericFileName) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "job_failed", &errMsg) return err } @@ -61,22 +65,29 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro // Uploading MCAP file to S3 mcapFileS3Reader, err := os.Open(job.FilePath) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "mcap_upload_failed", &errMsg) log.Fatalf("could not open mcap file %v", job.FilePath) } defer mcapFileS3Reader.Close() - recordId := primitive.NewObjectID() + // recordId := primitive.NewObjectID() moved to top mcapFileName := job.Filename mcapObjectFilePath := fmt.Sprintf("%s/%s", recordId.Hex(), mcapFileName) err = fp.s3Repository.WriteObjectReader(ctx, mcapFileS3Reader, mcapObjectFilePath) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "mcap_upload_failed", &errMsg) log.Fatal(err) } + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "mcap_uploaded", nil) log.Printf("uploaded mcap file %v to s3", mcapFileName) // Uploading HDF5 file to S3 hdf5File, err := os.Open(hdf5Location) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "hdf5_failed", &errMsg) log.Fatalf("could not open mat matFile: %v", err) } defer hdf5File.Close() @@ -85,8 +96,11 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro matObjectFilePath := fmt.Sprintf("%s/%s", recordId.Hex(), hdf5FileName) err = fp.s3Repository.WriteObjectReader(ctx, hdf5File, matObjectFilePath) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "hdf5_failed", &errMsg) log.Fatal(err) } + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "hdf5_uploaded", nil) log.Printf("uploaded hdf5 file %v to s3", hdf5FileName) // Uploading Lat-Lon file to S3 @@ -94,8 +108,11 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro vnLatLonPlotFileObjectPath := fmt.Sprintf("%s/%s", recordId.Hex(), vnLatLonPlotName) err = fp.s3Repository.WriteObjectWriterTo(ctx, vnLatLonPlotWriter, vnLatLonPlotFileObjectPath) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "plots_failed", &errMsg) log.Fatal(err) } + // _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "plots_uploaded", nil) log.Printf("uploaded vn lat lon plot %v to s3", vnLatLonPlotName) // Uploading Time-Vel file to S3 @@ -103,8 +120,11 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro vnTimeVelPlotFileObjectPath := fmt.Sprintf("%s/%s", recordId.Hex(), vnTimeVelPlotName) err = fp.s3Repository.WriteObjectWriterTo(ctx, vnTimeVelPlotWriter, vnTimeVelPlotFileObjectPath) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "plots_failed", &errMsg) log.Fatal(err) } + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "plots_uploaded", nil) log.Printf("uploaded vn time vel plot %v to s3", vnTimeVelPlotName) // After successful processing, if we are in PRODUCTION, save the mcap and h5 file to our docker volume @@ -193,6 +213,8 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro _, err = fp.dbClient.VehicleRunUseCase().CreateVehicleRun(ctx, vehicleRunModel) if err != nil { + errMsg := err.Error() + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "job_failed", &errMsg) log.Fatal(err) } @@ -202,6 +224,7 @@ func (p *PostProcessMCAPUploadJob) Process(fp *FileProcessor, job *FileJob) erro fp.updateJobStatus(job, StatusCompleted) fp.setCurrentlyProcessing(false) + _, _ = fp.dbClient.EventsUseCase().LogEvent(ctx, recordId, job.Filename, "job_completed", nil) log.Printf("Completed job %v", job.ID) return nil } diff --git a/cloud_webserver_v2/internal/database/database.go b/cloud_webserver_v2/internal/database/database.go index 680809b..d7ed8ec 100644 --- a/cloud_webserver_v2/internal/database/database.go +++ b/cloud_webserver_v2/internal/database/database.go @@ -18,6 +18,7 @@ type DatabaseClient struct { databaseClient *mongo.Client vehicleRunRepository repository.VehicleRunRepository carMetricsRepository repository.CarMetricsRepository + eventsRepository repository.EventsRepository } const VehicleDataDatabase = "vehicle_data_db" @@ -55,6 +56,12 @@ func NewDatabaseClient(ctx context.Context, uri string) (*DatabaseClient, error) } databaseClient.carMetricsRepository = carMetricsRepository + eventsRepository, err := repository.NewMongoEventsRepository(client, vehicleDataDatabase) + if err != nil { + return nil, fmt.Errorf("could not create eventsRepository: %v", err) + } + databaseClient.eventsRepository = eventsRepository + return databaseClient, nil } @@ -66,6 +73,10 @@ func (client *DatabaseClient) CarMetricsUseCase() *usecase.CarMetricsUseCase { return usecase.NewCarMetricsUseCase(client.carMetricsRepository) } +func (client *DatabaseClient) EventsUseCase() *usecase.EventsUseCase { + return usecase.NewEventsUseCase(client.eventsRepository) +} + func (client *DatabaseClient) Disonnect(ctx context.Context) error { err := client.databaseClient.Disconnect(ctx) if err != nil { diff --git a/cloud_webserver_v2/internal/database/repository/events_repository.go b/cloud_webserver_v2/internal/database/repository/events_repository.go new file mode 100644 index 0000000..fe1e0cb --- /dev/null +++ b/cloud_webserver_v2/internal/database/repository/events_repository.go @@ -0,0 +1,109 @@ +package repository + +import ( + "context" + "fmt" + + "github.com/hytech-racing/cloud-webserver-v2/internal/models" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +const EventsCollection string = "events" + +type EventsRepository interface { + Save(ctx context.Context, events *models.EventsModel) (*models.EventsModel, error) + GetWithEventsFilters(ctx context.Context, filters *bson.M) ([]models.EventsModel, error) + GetEventsFromId(ctx context.Context, id primitive.ObjectID) (*models.EventsModel, error) + DeleteEventsFromId(ctx context.Context, id primitive.ObjectID) error + UpdateEventsFromId(ctx context.Context, id primitive.ObjectID, events *models.EventsModel) error +} + +type MongoEventsRepository struct { + dbClient *mongo.Client + db *mongo.Database + collection *mongo.Collection +} + +func NewMongoEventsRepository(dbClient *mongo.Client, database *mongo.Database) (*MongoEventsRepository, error) { + collection := database.Collection(EventsCollection) + if collection == nil { + return nil, fmt.Errorf("could not get collection %s", EventsCollection) + } + + return &MongoEventsRepository{ + dbClient: dbClient, + db: database, + collection: collection, + }, nil +} + +// Inserts a EventsModel into the MongoDB database +func (repo *MongoEventsRepository) Save(ctx context.Context, events *models.EventsModel) (*models.EventsModel, error) { + res, err := repo.collection.InsertOne(ctx, events) + if err != nil { + return nil, fmt.Errorf("could not insert events data: %v, received error: %v", events, err) + } + + events.ID = res.InsertedID.(primitive.ObjectID) + return events, nil +} + +// Get a EventsModel from the MongoDB database with filters +func (repo *MongoEventsRepository) GetWithEventsFilters(ctx context.Context, filters *bson.M) ([]models.EventsModel, error) { + cursor, err := repo.collection.Find(ctx, filters) + if err != nil { + return nil, fmt.Errorf("could not find in events data with filters %v, received error: %v", filters, err) + } + + var modelResults []models.EventsModel + + if err = cursor.All(ctx, &modelResults); err != nil { + return nil, err + } + + if modelResults == nil { + modelResults = make([]models.EventsModel, 0) + } + + return modelResults, nil +} + +// Get a EventsModel from the MongoDB database from a Events ID +func (repo *MongoEventsRepository) GetEventsFromId(ctx context.Context, id primitive.ObjectID) (*models.EventsModel, error) { + filter := bson.M{"_id": id} + result := repo.collection.FindOne(ctx, filter) + if result.Err() != nil { + return nil, result.Err() + } + + var model models.EventsModel + err := result.Decode(&model) + if err != nil { + return nil, fmt.Errorf("could not decode result into model: %v", err) + } + + return &model, nil +} + +// Delete a EventsModel from the MongoDB database from a Events ID +func (repo *MongoEventsRepository) DeleteEventsFromId(ctx context.Context, id primitive.ObjectID) error { + filter := bson.M{"_id": id} + _, err := repo.collection.DeleteOne(ctx, filter) + if err != nil { + return err + } + + return nil +} + +// Updates a EventsModel from the MongoDB database from a Events ID and given Events +func (repo *MongoEventsRepository) UpdateEventsFromId(ctx context.Context, id primitive.ObjectID, events *models.EventsModel) error { + filter := bson.M{"_id": id} + resp := repo.collection.FindOneAndReplace(ctx, filter, events) + if resp.Err() != nil { + return resp.Err() + } + return nil +} diff --git a/cloud_webserver_v2/internal/database/usecase/events_usecase.go b/cloud_webserver_v2/internal/database/usecase/events_usecase.go new file mode 100644 index 0000000..013fe51 --- /dev/null +++ b/cloud_webserver_v2/internal/database/usecase/events_usecase.go @@ -0,0 +1,91 @@ +package usecase + +import ( + "context" + + "github.com/hytech-racing/cloud-webserver-v2/internal/database/repository" + "github.com/hytech-racing/cloud-webserver-v2/internal/models" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +type EventsUseCase struct { + EventsRepo repository.EventsRepository +} + +func NewEventsUseCase(eventsRepo repository.EventsRepository) *EventsUseCase { + return &EventsUseCase{ + EventsRepo: eventsRepo, + } +} + +func (uc *EventsUseCase) CreateEvents(ctx context.Context, model *models.EventsModel) (*models.EventsModel, error) { + model, err := uc.EventsRepo.Save(ctx, model) + if err != nil { + return nil, err + } + return model, nil +} + +func (uc *EventsUseCase) GetEventsByFilters(ctx context.Context, filters *models.EventsModelFilters) ([]models.EventsModel, error) { + bson_filters_m := bson.M{} + bson_or := bson.A{} + + if filters.ID != nil { + id, err := primitive.ObjectIDFromHex(filters.ID.Hex()) + if err != nil { + return nil, err + } + bson_filters_m["id"] = id + } + + if filters.BeforeDate != nil || filters.AfterDate != nil { + dateFilter := bson.M{} + if filters.BeforeDate != nil { + dateFilter["$gte"] = *filters.BeforeDate + } + if filters.AfterDate != nil { + dateFilter["$lte"] = *filters.AfterDate + } + bson_filters_m["date"] = dateFilter + } + + if filters.EventType != nil { + bson_filters_m["event_type"] = bson.M{"$regex": primitive.Regex{Pattern: *filters.EventType, Options: "i"}} + } + + if len(bson_or) != 0 { + bson_filters_m["$or"] = bson_or + } + + result, err := uc.EventsRepo.GetWithEventsFilters(context.TODO(), &bson_filters_m) + if err != nil { + return nil, err + } + + return result, nil +} + +func (uc *EventsUseCase) GetEventsById(ctx context.Context, id primitive.ObjectID) (*models.EventsModel, error) { + return uc.EventsRepo.GetEventsFromId(ctx, id) +} + +func (uc *EventsUseCase) DeleteEventsById(ctx context.Context, id primitive.ObjectID) error { + return uc.EventsRepo.DeleteEventsFromId(ctx, id) +} + +func (uc *EventsUseCase) UpdateEventsRun(ctx context.Context, id primitive.ObjectID, model *models.EventsModel) error { + return uc.EventsRepo.UpdateEventsFromId(ctx, id, model) +} +func (uc *EventsUseCase) LogEvent(ctx context.Context, mcapID primitive.ObjectID, filename string, event string, errMsg *string) (*models.EventsModel, error) { + now := time.Now() + model := &models.EventsModel{ + McapID: &mcapID, + McapFilename: &filename, + Event: &event, + Error: errMsg, + CreatedAt: &now, + } + return uc.CreateEvents(ctx, model) +} diff --git a/cloud_webserver_v2/internal/models/events_filters_model.go b/cloud_webserver_v2/internal/models/events_filters_model.go new file mode 100644 index 0000000..9997427 --- /dev/null +++ b/cloud_webserver_v2/internal/models/events_filters_model.go @@ -0,0 +1,16 @@ +package models + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +// VehicleRunModelFilters contians all the possible ways to filter and query +// for a VehicleRun. +type EventsModelFilters struct { + ID *primitive.ObjectID `bson:"id",omitempty` + BeforeDate *time.Time `bson:"before_date,omitempty"` + AfterDate *time.Time `bson:"after_date,omitempty"` + EventType *string `bson:"event_type",omitempty` +} diff --git a/cloud_webserver_v2/internal/models/events_model.go b/cloud_webserver_v2/internal/models/events_model.go new file mode 100644 index 0000000..2c9dc9d --- /dev/null +++ b/cloud_webserver_v2/internal/models/events_model.go @@ -0,0 +1,17 @@ +package models + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +// Events: job_started, mcap_uploaded, hdf5_uploaded, plots_uploaded, job_completed, hdf5_failed, job_failed +type EventsModel struct { + ID primitive.ObjectID `bson:"_id,omitempty"` + McapID *primitive.ObjectID `bson:"mcap_id,omitempty"` + McapFilename *string `bson:"mcap_filename,omitempty"` + Event *string `bson:"event,omitempty"` + Error *string `bson:"error,omitempty"` + CreatedAt *time.Time `bson:"created_at,omitempty"` +} From 7e8c10c51c7f61787ed2b3318b1ab18a75384b21 Mon Sep 17 00:00:00 2001 From: janista-ng Date: Thu, 23 Apr 2026 19:05:27 -0400 Subject: [PATCH 14/14] removed mcap file name --- cloud_webserver_v2/internal/database/usecase/events_usecase.go | 1 - cloud_webserver_v2/internal/models/events_model.go | 1 - 2 files changed, 2 deletions(-) diff --git a/cloud_webserver_v2/internal/database/usecase/events_usecase.go b/cloud_webserver_v2/internal/database/usecase/events_usecase.go index 013fe51..9d5191f 100644 --- a/cloud_webserver_v2/internal/database/usecase/events_usecase.go +++ b/cloud_webserver_v2/internal/database/usecase/events_usecase.go @@ -82,7 +82,6 @@ func (uc *EventsUseCase) LogEvent(ctx context.Context, mcapID primitive.ObjectID now := time.Now() model := &models.EventsModel{ McapID: &mcapID, - McapFilename: &filename, Event: &event, Error: errMsg, CreatedAt: &now, diff --git a/cloud_webserver_v2/internal/models/events_model.go b/cloud_webserver_v2/internal/models/events_model.go index 2c9dc9d..ffe3284 100644 --- a/cloud_webserver_v2/internal/models/events_model.go +++ b/cloud_webserver_v2/internal/models/events_model.go @@ -10,7 +10,6 @@ import ( type EventsModel struct { ID primitive.ObjectID `bson:"_id,omitempty"` McapID *primitive.ObjectID `bson:"mcap_id,omitempty"` - McapFilename *string `bson:"mcap_filename,omitempty"` Event *string `bson:"event,omitempty"` Error *string `bson:"error,omitempty"` CreatedAt *time.Time `bson:"created_at,omitempty"`