From 94115067c47fdc6c8b1f31a5aa37fb11c9ee1075 Mon Sep 17 00:00:00 2001 From: Steve White Date: Sun, 6 Oct 2024 18:02:38 -0500 Subject: [PATCH] fixed image upload, patched up tests.bash --- .gitignore | 1 + config.yaml | 2 +- db.go | 8 +++--- handlers.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 4 +++ tests.bash | 44 +++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 772fdf0..f2e28c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ data/boxes.db +images/* \ No newline at end of file diff --git a/config.yaml b/config.yaml index 9713c08..cc647fe 100644 --- a/config.yaml +++ b/config.yaml @@ -1,6 +1,6 @@ database_path: "data/boxes.db" test_database_path: "data/test_database.db" jwt_secret: "super_secret_key" -image_storage_dir: "images/" +image_storage_dir: "./images/" listening_port: 8080 log_file: "boxes.log" \ No newline at end of file diff --git a/db.go b/db.go index 0b0efb4..1c32e12 100644 --- a/db.go +++ b/db.go @@ -16,10 +16,10 @@ type Box struct { // Define the Item model type Item struct { gorm.Model - Name string `json:"name"` - Description string `json:"description"` - BoxID uint `json:"box_id"` - ImagePath *string `json:"image_path"` + Name string `json:"name"` + Description string `json:"description"` + BoxID uint `json:"box_id"` + ImagePath string `json:"image_path"` } // Define the User model diff --git a/handlers.go b/handlers.go index 0122399..266bf14 100644 --- a/handlers.go +++ b/handlers.go @@ -4,7 +4,9 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" + "os" "strings" "time" @@ -149,6 +151,75 @@ func CreateItemHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(response) } +// UploadItemImageHandler handles the image upload for an item +func UploadItemImageHandler(w http.ResponseWriter, r *http.Request) { + // Extract the authenticated user from context (assuming this is how AuthMiddleware works) + user, ok := r.Context().Value(userKey).(string) + if !ok || user == "" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Parse the form data, 10MB limit for file uploads + err := r.ParseMultipartForm(10 << 20) + if err != nil { + http.Error(w, "Unable to parse form", http.StatusBadRequest) + return + } + + // Get the file from the form data + file, handler, err := r.FormFile("image") + if err != nil { + http.Error(w, "Error retrieving the file", http.StatusBadRequest) + return + } + defer file.Close() + + // Get item ID from the URL + vars := mux.Vars(r) + itemID := vars["id"] + + // Validate that the item exists (fetch from DB using itemID) + var item Item + if err := db.First(&item, itemID).Error; err != nil { + http.Error(w, "Item not found", http.StatusNotFound) + return + } + + // Save the uploaded file locally or to a storage service + // Ensure the directory exists + if err := os.MkdirAll(config.ImageStorageDir, 0755); err != nil { + http.Error(w, "Unable to create image storage directory", http.StatusInternalServerError) + return + } + + filePath := fmt.Sprintf("%s/%s", config.ImageStorageDir, handler.Filename) + outFile, err := os.Create(filePath) + if err != nil { + http.Error(w, "Unable to save the file", http.StatusInternalServerError) + return + } + defer outFile.Close() + + // Copy the uploaded file to the destination + _, err = io.Copy(outFile, file) + if err != nil { + http.Error(w, "Unable to save the file", http.StatusInternalServerError) + return + } + + // Update the item record in the database with the image path + item.ImagePath = filePath + if err := db.Save(&item).Error; err != nil { + http.Error(w, "Unable to save image path in database", http.StatusInternalServerError) + return + } + + // Return the image path in the response + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]string{"imagePath": filePath}) +} + // getItemHandler handles the GET /items/{id} endpoint. func GetItemHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diff --git a/main.go b/main.go index a69e060..dc39776 100644 --- a/main.go +++ b/main.go @@ -51,6 +51,10 @@ func main() { router.Handle("/items/{id}/items", AuthMiddleware(http.HandlerFunc(GetItemsInBoxHandler))).Methods("GET", "OPTIONS") router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(UpdateItemHandler))).Methods("PUT", "OPTIONS") router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(DeleteItemHandler))).Methods("DELETE", "OPTIONS") + // Add a new route for uploading an image with AuthMiddleware + router.HandleFunc("/items/{id}/upload", UploadItemImageHandler). + Methods("POST"). + Handler(AuthMiddleware(http.HandlerFunc(UploadItemImageHandler))) // Apply CORS middleware c := cors.New(cors.Options{ diff --git a/tests.bash b/tests.bash index 5a44e60..2c9ec7b 100755 --- a/tests.bash +++ b/tests.bash @@ -110,6 +110,48 @@ else echo "$response" fi +# 11. Create Image and Assign to Item (Assuming an item with ID $ITEM_ID exists) +echo +echo +echo "Testing /items/$ITEM_ID/upload (POST)..." + +# Get a new JWT token +TOKEN=$(curl -s -X POST -H "Content-Type: application/json" \ + -d "{\"username\":\"$USERNAME\", \"password\":\"$PASSWORD\"}" \ + "$API_BASE_URL/login" | jq -r '.token') + +# Create a temporary image file +IMAGE_FILE=$(mktemp /tmp/test_image.XXXXXX) +echo "Test Image Content" > "$IMAGE_FILE" + +echo "Token is $TOKEN" + +# Make the request using curl to upload the image +response=$(curl -s -w "%{http_code}" -X POST \ + -H "Authorization: Bearer $(echo "$TOKEN")" \ + -F "image=@$IMAGE_FILE" \ + "$API_BASE_URL/items/$ITEM_ID/upload") + +echo $response + +# Separate the body and the HTTP status code +http_status=$(echo "$response" | tail -n1) +body=$(echo "$response" | sed '$d') + +# Remove the temporary image file +rm "$IMAGE_FILE" + +# Check if the HTTP status is 200 (OK) and the imagePath is returned +if [[ "$http_status" == "200" && $(echo "$body" | jq -r '.imagePath') != "null" ]]; then + echo -e "\033[32m /items/$ITEM_ID/upload (POST): PASS\033[0m" # Green PASS + IMAGE_PATH=$(echo "$body" | jq -r '.imagePath') + echo "Image Path: $IMAGE_PATH" +else + echo -e "\033[31m /items/$ITEM_ID/upload (POST): FAIL (Invalid response or no imagePath)\033[0m" # Red FAIL + echo "Response: $response" +fi + + # 6. Get Items echo echo "Testing /items (GET)..." @@ -130,6 +172,8 @@ echo echo "Testing /items/{id} (GET)..." response=$(authenticated_request "GET" "/items/$ITEM_ID" "") +echo $response | jq . + # Check if the request was successful AND if the response ID matches $ITEM_ID if [[ $? -eq 0 ]] && [[ $(echo "$response" | jq -r '.ID') == "$ITEM_ID" ]]; then echo -e "\033[32m /items/{id} (GET): PASS\033[0m" # Green PASS