diff --git a/bruno/library/Delete Library Folder.bru b/bruno/library/Delete Library Folder.bru new file mode 100644 index 0000000..7dbbe76 --- /dev/null +++ b/bruno/library/Delete Library Folder.bru @@ -0,0 +1,75 @@ +meta { + name: Delete Library Folder + type: http + seq: 4 +} + +delete { + url: {{base_url}}/api/libraries/{{library_id}}/folders + body: json + auth: inherit +} + +headers { + Content-Type: application/json +} + +body:json { + "folder_path": "/path/to/folder" +} + +tests { + test_delete_library_folder_success(status, headers, body) { + if (status !== 204) { + throw new Error("Expected status 204, got " + status); + } + + // Delete should return no content + if (body && body.length > 0) { + throw new Error("Expected empty response body for delete"); + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23c3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Delete Library Folder + + Removes a folder from a library's scanning configuration. + + **Method:** DELETE + + **Endpoint:** /api/libraries/{id}/folders + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Library UUID + + **Request Body:** + - `folder_path` (string, required): Path to folder to remove + + **Response:** Empty (204 No Content) + + **Status Codes:** + - 204: Folder deleted successfully + - 400: Invalid request data + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Examples:** + - Delete folder: `DELETE /api/libraries/cc23c3a7-f8fb-451a-a78d-2a16df1b725a/folders` + + **Note:** Admin access required - only users with admin role can manage library folders. +} \ No newline at end of file diff --git a/bruno/library/Delete Library.bru b/bruno/library/Delete Library.bru new file mode 100644 index 0000000..451d200 --- /dev/null +++ b/bruno/library/Delete Library.bru @@ -0,0 +1,71 @@ +meta { + name: Delete Library + type: http + seq: 3 +} + +delete { + url: {{base_url}}/api/libraries/{{library_id}} + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_delete_library_success(status, headers, body) { + if (status !== 204) { + throw new Error("Expected status 204, got " + status); + } + + // Delete should return no content + if (body && body.length > 0) { + throw new Error("Expected empty response body for delete"); + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23c3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Delete Library + + Deletes a library and all associated media items. + + **Method:** DELETE + + **Endpoint:** /api/libraries/{id} + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Library UUID + + **Response:** Empty (204 No Content) + + **Status Codes:** + - 204: Library deleted successfully + - 400: Invalid library ID + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Warning:** This will delete ALL media items in the library. + + **Examples:** + - Delete library: `DELETE /api/libraries/cc23c3a7-f8fb-451a-a78d-2a16df1b725a` + + **Note:** Admin access required - only users with admin role can delete libraries. +} \ No newline at end of file diff --git a/bruno/library/Get Library Stats.bru b/bruno/library/Get Library Stats.bru new file mode 100644 index 0000000..5f95b0d --- /dev/null +++ b/bruno/library/Get Library Stats.bru @@ -0,0 +1,92 @@ +meta { + name: Get Library Stats + type: http + seq: 5 +} + +get { + url: {{base_url}}/api/libraries/{{library_id}}/stats + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_get_library_stats_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + const contentType = headers["content-type"]; + if (!contentType || !contentType.includes("application/json")) { + throw new Error("Expected content-type to contain application/json, got " + contentType); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data || typeof data !== "object") { + throw new Error("Expected stats object in response"); + } + + // Expected fields (verify they exist) + const expectedFields = ["total_items", "total_size", "scanned_at"]; + for (const field of expectedFields) { + if (!(field in data)) { + console.warn("Stats field '" + field + "' is missing from response"); + } + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23d3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Get Library Stats + + Retrieves statistical information about a library's media items. + + **Method:** GET + + **Endpoint:** /api/libraries/{id}/stats + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Library UUID + + **Response:** Stats object + - `total_items` (number): Total media items in library + - `total_size` (number): Total file size in bytes + - `scanned_at` (string): Last scan timestamp + - Additional fields may be included + + **Status Codes:** + - 200: Success + - 400: Invalid library ID + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Examples:** + - Get library stats: `GET /api/libraries/cc23c3a7-f8fb-451a-a78d-2a16df1b725a/stats` + + **Note:** Admin access required - only users with admin role can access library statistics. +} \ No newline at end of file diff --git a/bruno/library/Get Library.bru b/bruno/library/Get Library.bru new file mode 100644 index 0000000..3f9b623 --- /dev/null +++ b/bruno/library/Get Library.bru @@ -0,0 +1,92 @@ +meta { + name: Get Library + type: http + seq: 1 +} + +get { + url: {{base_url}}/api/libraries/{{library_id}} + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_get_library_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + const contentType = headers["content-type"]; + if (!contentType || !contentType.includes("application/json")) { + throw new Error("Expected content-type to contain application/json, got " + contentType); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + // Verify library object structure + if (!data || typeof data !== "object") { + throw new Error("Expected library object in response"); + } + + // Required fields + if (!data.id || !data.name || !data.library_type_id) { + throw new Error("Library missing required fields: id, name, library_type_id"); + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23c3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Get Library + + Retrieves detailed information about a specific library by ID. + + **Method:** GET + + **Endpoint:** /api/libraries/{id} + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Library UUID + + **Response:** Library object + - `id` (string): Library UUID + - `name` (string): Library name + - `description` (string): Library description + - `library_type_id` (string): Library type UUID + - `created_by_admin_id` (string): Admin UUID who created it + - `created_at` (string): Creation timestamp + - `updated_at` (string): Last update timestamp + + **Status Codes:** + - 200: Success + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Examples:** + - Get library: `GET /api/libraries/cc23c3a7-f8fb-451a-a78d-2a16df1b725a` + + **Note:** Admin access required - only users with admin role can access library details. +} \ No newline at end of file diff --git a/bruno/library/Update Library.bru b/bruno/library/Update Library.bru new file mode 100644 index 0000000..f1fcb21 --- /dev/null +++ b/bruno/library/Update Library.bru @@ -0,0 +1,93 @@ +meta { + name: Update Library + type: http + seq: 2 +} + +put { + url: {{base_url}}/api/libraries/{{library_id}} + body: json + auth: inherit +} + +headers { + Content-Type: application/json +} + +body:json { + "name": "Updated Library Name", + "description": "Updated library description" +} + +tests { + test_update_library_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data || typeof data !== "object") { + throw new Error("Expected updated library object in response"); + } + + if (!data.id || !data.updated_at) { + throw new Error("Library response missing update confirmation"); + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23c3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Update Library + + Updates an existing library's information. + + **Method:** PUT + + **Endpoint:** /api/libraries/{id} + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Library UUID + + **Request Body:** + - `name` (string, optional): Library name + - `description` (string, optional): Library description + + **Response:** Updated library object + - `id` (string): Library UUID + - `name` (string): Updated library name + - `description` (string): Updated library description + - `library_type_id` (string): Library type UUID + - `updated_at` (string): Update timestamp + + **Status Codes:** + - 200: Success + - 400: Invalid request data + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Examples:** + - Update library: `PUT /api/libraries/cc23c3a7-f8fb-451a-a78d-2a16df1b725a` + + **Note:** Admin access required - only users with admin role can update libraries. +} \ No newline at end of file diff --git a/bruno/media-items/Create Media Item.bru b/bruno/media-items/Create Media Item.bru new file mode 100644 index 0000000..8ef15d5 --- /dev/null +++ b/bruno/media-items/Create Media Item.bru @@ -0,0 +1,125 @@ +meta { + name: Create Media Item + type: http + seq: 1 +} + +post { + url: {{base_url}}/api/media-items + body: json + auth: inherit +} + +headers { + Content-Type: application/json +} + +body:json { + "library_id": "{{library_id}}", + "title": "New Media Item", + "author": "Author Name", + "isbn": "978-0123456789", + "description": "Description of the media item", + "cover_image_path": "/path/to/cover.jpg", + "series": "Series Name", + "series_number": 1, + "tags": "fiction, adventure", + "asin": "B08XYZ123", + "date_published": "2023-01-15", + "publisher": "Publisher Name", + "contributors": "Contributor Name", + "language": "en", + "edition": "First Edition", + "page_count": 350, + "genre": "Science Fiction", + "copyright_year": 2023, + "goodreads_id": "123456", + "openlibrary_id": "OL123456M", + "google_books_id": "GB123456" +} + +tests { + test_create_media_item_success(status, headers, body) { + if (status !== 201) { + throw new Error("Expected status 201, got " + status); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data || typeof data !== "object") { + throw new Error("Expected media item object in response"); + } + + // Verify required fields + if (!data.id || !data.title || !data.library_id) { + throw new Error("Media item missing required fields: id, title, library_id"); + } + + return true; + } +} + +vars:pre-request { + libraryId: "cc23c3a7-f8fb-451a-a78d-2a16df1b725a" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Create Media Item + + Creates a new media item in a library with full metadata. + + **Method:** POST + + **Endpoint:** /api/media-items + + **Authentication:** Required (Bearer token, admin only) + + **Request Body:** + - `library_id` (string, required): Library UUID + - `title` (string, required): Media item title + - `author` (string, optional): Author name + - `isbn` (string, optional): ISBN number + - `description` (string, optional): Description + - `cover_image_path` (string, optional): Path to cover image + - `series` (string, optional): Series name + - `series_number` (integer, optional): Number in series + - `tags` (string, optional): Tags or categories + - `asin` (string, optional): Amazon ASIN + - `date_published` (string, optional): Publication date + - `publisher` (string, optional): Publisher name + - `contributors` (string, optional): Contributors + - `language` (string, optional): Language code (ISO 639-1) + - `edition` (string, optional): Edition information + - `page_count` (integer, optional): Total page count + - `genre` (string, optional): Genre classification + - `copyright_year` (integer, optional): Copyright year + - `goodreads_id` (string, optional): Goodreads identifier + - `openlibrary_id` (string, optional): Open Library identifier + - `google_books_id` (string, optional): Google Books identifier + + **Response:** Created media item object + - All fields above plus system-generated fields + + **Status Codes:** + - 201: Media item created successfully + - 400: Invalid request data + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Library not found + - 500: Internal server error + + **Examples:** + - Create media item: `POST /api/media-items` + + **Note:** Admin access required - only users with admin role can create media items. +} \ No newline at end of file diff --git a/bruno/media-items/Delete Media Item.bru b/bruno/media-items/Delete Media Item.bru new file mode 100644 index 0000000..5a0a809 --- /dev/null +++ b/bruno/media-items/Delete Media Item.bru @@ -0,0 +1,71 @@ +meta { + name: Delete Media Item + type: http + seq: 3 +} + +delete { + url: {{base_url}}/api/media-items/{{media_item_id}} + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_delete_media_item_success(status, headers, body) { + if (status !== 204) { + throw new Error("Expected status 204, got " + status); + } + + // Delete should return no content + if (body && body.length > 0) { + throw new Error("Expected empty response body for delete"); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "550e8400-e29b-41d4-a716-446655440000" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Delete Media Item + + Deletes a media item from the library. + + **Method:** DELETE + + **Endpoint:** /api/media-items/{id} + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Media item UUID + + **Response:** Empty (204 No Content) + + **Status Codes:** + - 204: Media item deleted successfully + - 400: Invalid media item ID + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Media item not found + - 500: Internal server error + + **Examples:** + - Delete media item: `DELETE /api/media-items/550e8400-e29b-41d4-a716-446655440000` + + **Warning:** This permanently removes the media item and all associated data (ratings, notes, highlights). + + **Note:** Admin access required - only users with admin role can delete media items. +} \ No newline at end of file diff --git a/bruno/media-items/Delete Media Rating.bru b/bruno/media-items/Delete Media Rating.bru new file mode 100644 index 0000000..537af50 --- /dev/null +++ b/bruno/media-items/Delete Media Rating.bru @@ -0,0 +1,67 @@ +meta { + name: Delete Media Rating + type: http + seq: 5 +} + +delete { + url: {{base_url}}/api/media-items/{{media_item_id}}/rating + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_delete_media_rating_success(status, headers, body) { + if (status !== 204) { + throw new Error("Expected status 204, got " + status); + } + + // Delete should return no content + if (body && body.length > 0) { + throw new Error("Expected empty response body for delete"); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "550e8400-e29b-41d4-a716-446655440000" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Delete Media Rating + + Deletes a user's rating for a specific media item. + + **Method:** DELETE + + **Endpoint:** /api/media-items/{id}/rating + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string): Media item UUID + + **Response:** Empty (204 No Content) + + **Status Codes:** + - 204: Rating deleted successfully + - 401: Unauthorized + - 404: Media item not found + - 500: Internal server error + + **Examples:** + - Delete media rating: `DELETE /api/media-items/550e8400-e29b-41d4-a716-446655440000/rating` + + **Note:** Deletes only the authenticated user's rating, not other users' ratings. +} \ No newline at end of file diff --git a/bruno/media-items/Get Media Rating.bru b/bruno/media-items/Get Media Rating.bru new file mode 100644 index 0000000..2cbe9c9 --- /dev/null +++ b/bruno/media-items/Get Media Rating.bru @@ -0,0 +1,84 @@ +meta { + name: Get Media Rating + type: http + seq: 4 +} + +get { + url: {{base_url}}/api/media-items/{{media_item_id}}/rating + body: none + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_get_media_rating_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data || typeof data !== "object") { + throw new Error("Expected rating object in response"); + } + + // Verify expected fields + if (!data.media_item_id || !data.rating === undefined) { + throw new Error("Rating response missing required fields: media_item_id, rating"); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "550e8400-e29b-41d4-a716-446655440000" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Get Media Rating + + Retrieves a user's rating for a specific media item. + + **Method:** GET + + **Endpoint:** /api/media-items/{id}/rating + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string): Media item UUID + + **Response:** Rating object + - `id` (string): Rating UUID + - `media_item_id` (string): Media item UUID + - `user_id` (string): User UUID + - `rating` (integer): Rating value (1-10 scale) + - `created_at` (string): Creation timestamp + - `updated_at` (string): Last update timestamp + + **Status Codes:** + - 200: Success + - 401: Unauthorized + - 404: Media item not found + - 500: Internal server error + + **Examples:** + - Get media rating: `GET /api/media-items/550e8400-e29b-41d4-a716-446655440000/rating` + + **Note:** Returns the authenticated user's rating for the specified media item. +} \ No newline at end of file diff --git a/bruno/media-items/Update Media Item.bru b/bruno/media-items/Update Media Item.bru new file mode 100644 index 0000000..5737c87 --- /dev/null +++ b/bruno/media-items/Update Media Item.bru @@ -0,0 +1,104 @@ +meta { + name: Update Media Item + type: http + seq: 2 +} + +put { + url: {{base_url}}/api/media-items/{{media_item_id}} + body: json + auth: inherit +} + +headers { + Content-Type: application/json +} + +body:json { + "title": "Updated Media Item Title", + "author": "Updated Author Name", + "isbn": "978-9876543210", + "description": "Updated description", + "cover_image_path": "/updated/path/to/cover.jpg", + "series": "Updated Series Name", + "series_number": 2, + "tags": "updated, fiction, adventure", + "asin": "B09XYZ789", + "date_published": "2023-02-20", + "publisher": "Updated Publisher", + "contributors": "Updated Contributor", + "language": "en", + "edition": "Updated Edition", + "page_count": 400, + "genre": "Updated Genre", + "copyright_year": 2023, + "goodreads_id": "7890123", + "openlibrary_id": "OL789012M", + "google_books_id": "GB789012" +} + +tests { + test_update_media_item_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data || typeof data !== "object") { + throw new Error("Expected updated media item object in response"); + } + + if (!data.id || !data.updated_at) { + throw new Error("Media item response missing update confirmation"); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "550e8400-e29b-41d4-a716-446655440000" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Update Media Item + + Updates an existing media item's metadata. + + **Method:** PUT + + **Endpoint:** /api/media-items/{id} + + **Authentication:** Required (Bearer token, admin only) + + **Path Parameters:** + - `id` (string): Media item UUID + + **Request Body:** All media item fields (same as Create) + + **Response:** Updated media item object + + **Status Codes:** + - 200: Media item updated successfully + - 400: Invalid request data + - 401: Unauthorized + - 403: Forbidden (admin access required) + - 404: Media item not found + - 500: Internal server error + + **Examples:** + - Update media item: `PUT /api/media-items/550e8400-e29b-41d4-a716-446655440000` + + **Note:** Admin access required - only users with admin role can update media items. +} \ No newline at end of file