diff --git a/.devcontainer/collection.json b/.devcontainer/thunder_client_collection.json similarity index 59% rename from .devcontainer/collection.json rename to .devcontainer/thunder_client_collection.json index 9a6b5d5e..91a4ee7d 100644 --- a/.devcontainer/collection.json +++ b/.devcontainer/thunder_client_collection.json @@ -1,20 +1,20 @@ { "client": "Thunder Client", "collectionName": "v1", - "dateExported": "2023-07-13T20:57:25.581Z", + "dateExported": "2023-07-30T22:30:18.191Z", "version": "1.1", "folders": [], "requests": [ { - "_id": "13a7489c-1f25-4574-8dc7-c24ff428d159", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "7bbe541b-26e4-4d46-8ff5-f7c772494e19", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Discover Subscriptions", "url": "/v1/discover", "method": "POST", "sortNum": 20000, - "created": "2023-07-13T19:58:25.996Z", - "modified": "2023-07-13T20:15:29.612Z", + "created": "2023-07-30T22:12:18.044Z", + "modified": "2023-07-30T22:12:18.044Z", "headers": [], "params": [], "body": { @@ -25,43 +25,43 @@ "tests": [] }, { - "_id": "50428a21-fde3-4761-b071-2aded5b85765", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "0f80623d-93a5-4bf5-b519-f509fb969889", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Feeds", "url": "/v1/feeds", "method": "GET", "sortNum": 50000, - "created": "2023-07-13T20:02:06.400Z", - "modified": "2023-07-13T20:15:45.710Z", + "created": "2023-07-30T22:12:18.046Z", + "modified": "2023-07-30T22:12:18.046Z", "headers": [], "params": [], "tests": [] }, { - "_id": "b79c2ea4-a7a1-481c-8d09-00ae3b2589e8", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "f1f8ce8a-2d5d-4b99-ae21-ac2ddb43e7c3", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Category Feeds", "url": "/v1/categories/1/feeds", "method": "GET", "sortNum": 60000, - "created": "2023-07-13T20:02:18.690Z", - "modified": "2023-07-13T20:26:32.652Z", + "created": "2023-07-30T22:12:18.047Z", + "modified": "2023-07-30T22:12:18.047Z", "headers": [], "params": [], "tests": [] }, { - "_id": "e4926b94-f241-49e8-9de9-475fbab42674", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "0d462b4b-4d22-4832-b684-65ed932a7045", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Feed", "url": "/v1/feeds/{feedID}", "method": "GET", "sortNum": 70000, - "created": "2023-07-13T20:02:34.514Z", - "modified": "2023-07-13T20:45:47.579Z", + "created": "2023-07-30T22:12:18.048Z", + "modified": "2023-07-30T22:12:18.048Z", "headers": [], "params": [ { @@ -73,15 +73,15 @@ "tests": [] }, { - "_id": "b4e2579f-68c2-4010-86f3-c256a6766f53", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "a7e62c07-c09f-4fde-896c-26127ec5cefd", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Feed Icon ", "url": "/v1/feeds/{feedID}/icon", "method": "GET", "sortNum": 80000, - "created": "2023-07-13T20:02:52.263Z", - "modified": "2023-07-13T20:46:00.957Z", + "created": "2023-07-30T22:12:18.049Z", + "modified": "2023-07-30T22:12:18.049Z", "headers": [], "params": [ { @@ -93,15 +93,15 @@ "tests": [] }, { - "_id": "6cb12736-0f29-4579-a170-15068c862911", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "bc3465d1-8f76-4709-a143-e59308586fa9", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Create Feed ", "url": "/v1/feeds", "method": "POST", "sortNum": 90000, - "created": "2023-07-13T20:03:00.288Z", - "modified": "2023-07-13T20:34:58.793Z", + "created": "2023-07-30T22:12:18.050Z", + "modified": "2023-07-30T22:12:18.050Z", "headers": [], "params": [], "body": { @@ -112,15 +112,15 @@ "tests": [] }, { - "_id": "66458952-8912-4646-858c-0d371b654280", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "cd18e982-14e0-491f-85dc-a5b61d0ff9a0", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Update Feed", "url": "/v1/feeds/{feedID}", "method": "PUT", "sortNum": 100000, - "created": "2023-07-13T20:03:08.088Z", - "modified": "2023-07-13T20:46:34.052Z", + "created": "2023-07-30T22:12:18.051Z", + "modified": "2023-07-30T22:12:18.051Z", "headers": [], "params": [ { @@ -137,15 +137,15 @@ "tests": [] }, { - "_id": "ed460a11-135f-49a4-a975-17022246206a", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "02e422e4-45fe-4809-9121-6a9f13888a0f", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Refresh Feed", "url": "/v1/feeds/{feedID}/refresh", "method": "PUT", "sortNum": 110000, - "created": "2023-07-13T20:03:16.444Z", - "modified": "2023-07-13T20:46:44.021Z", + "created": "2023-07-30T22:12:18.052Z", + "modified": "2023-07-30T22:12:18.052Z", "headers": [], "params": [ { @@ -157,29 +157,29 @@ "tests": [] }, { - "_id": "c81da1ce-60b5-438a-b931-9af262fb2390", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "b5eca4d9-64fb-485b-8334-f9cf49ff2da2", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Refresh All Feeds", "url": "/v1/feeds/refresh", "method": "PUT", "sortNum": 115000, - "created": "2023-07-13T20:36:59.363Z", - "modified": "2023-07-13T20:37:34.197Z", + "created": "2023-07-30T22:12:18.082Z", + "modified": "2023-07-30T22:12:18.082Z", "headers": [], "params": [], "tests": [] }, { - "_id": "ef3be4f9-0673-4119-91e7-2c4d0e7e7374", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "85937b3d-dae0-48cb-9e42-1576cd7806cc", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Remove Feed", "url": "/v1/feeds/{feedID}", "method": "DELETE", "sortNum": 120000, - "created": "2023-07-13T20:03:24.716Z", - "modified": "2023-07-13T20:47:05.653Z", + "created": "2023-07-30T22:12:18.053Z", + "modified": "2023-07-30T22:12:18.053Z", "headers": [], "params": [ { @@ -191,15 +191,15 @@ "tests": [] }, { - "_id": "1e9b4b98-ad86-4679-8fc6-d49cf8d3da66", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "5113531a-b076-47e4-95cb-e77d3c4e74d5", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Feed Entry", "url": "/v1/feeds/{feedID}/entries", "method": "GET", "sortNum": 130000, - "created": "2023-07-13T20:03:35.916Z", - "modified": "2023-07-13T20:47:53.285Z", + "created": "2023-07-30T22:12:18.054Z", + "modified": "2023-07-30T22:12:18.054Z", "headers": [], "params": [ { @@ -211,35 +211,42 @@ "tests": [] }, { - "_id": "4b6c5fa8-d86e-46fd-821d-99629defcb91", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "bee7e21d-64e1-487b-9056-03f4d6aeb6e1", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Entry", "url": "/v1/entries/{entryID}", "method": "GET", "sortNum": 140000, - "created": "2023-07-13T20:03:46.247Z", - "modified": "2023-07-13T20:48:05.139Z", + "created": "2023-07-30T22:12:18.055Z", + "modified": "2023-07-30T22:23:59.036Z", "headers": [], "params": [ { "name": "entryID", - "value": "101", + "value": "1965", "isPath": true } ], + "auth": { + "type": "basic", + "basic": { + "username": "bob", + "password": "test123" + } + }, "tests": [] }, { - "_id": "3dfe4f29-8a9a-4263-9586-135cfc7a181d", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "9d071e33-c81d-4f79-b4ba-f6190fdfa7de", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Fetch original article", "url": "/v1/entries/{entryID}/fetch-content", "method": "GET", "sortNum": 150000, - "created": "2023-07-13T20:03:55.251Z", - "modified": "2023-07-13T20:48:13.702Z", + "created": "2023-07-30T22:12:18.056Z", + "modified": "2023-07-30T22:12:18.056Z", "headers": [], "params": [ { @@ -251,15 +258,15 @@ "tests": [] }, { - "_id": "ab3c80c4-57d6-458e-a215-bdd5b347e80a", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "a970f79a-2ab6-4e6e-b913-78786957520f", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Category Entries", "url": "/v1/categories/{categoryID}/entries", "method": "GET", "sortNum": 160000, - "created": "2023-07-13T20:04:04.963Z", - "modified": "2023-07-13T20:48:46.900Z", + "created": "2023-07-30T22:12:18.057Z", + "modified": "2023-07-30T22:12:18.057Z", "headers": [], "params": [ { @@ -271,55 +278,55 @@ "tests": [] }, { - "_id": "e881a806-ae4d-46f2-b46e-023aae5d134d", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "8c91c270-f562-456a-9112-f1631e8e34bd", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Feed Entries ", "url": "/v1/feeds/7/entries", "method": "GET", "sortNum": 170000, - "created": "2023-07-13T20:04:15.608Z", - "modified": "2023-07-13T20:49:57.241Z", + "created": "2023-07-30T22:12:18.058Z", + "modified": "2023-07-30T22:12:18.058Z", "headers": [], "params": [], "tests": [] }, { - "_id": "55dfde9e-52b6-48ad-9121-14cdd471d943", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "063c12b0-75c3-45fd-abbc-3d9179a73e96", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Mark Feed Entries as Read", "url": "", "method": "GET", "sortNum": 180000, - "created": "2023-07-13T20:04:27.605Z", - "modified": "2023-07-13T20:04:27.605Z", + "created": "2023-07-30T22:12:18.059Z", + "modified": "2023-07-30T22:12:18.059Z", "headers": [] }, { - "_id": "07e1caac-4d07-47e1-a110-c5d5109eee18", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "6eff1097-4cf9-4a9a-adc0-bcc4616fc1f4", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Entries", "url": "/v1/entries", "method": "GET", "sortNum": 190000, - "created": "2023-07-13T20:04:47.119Z", - "modified": "2023-07-13T20:40:13.594Z", + "created": "2023-07-30T22:12:18.060Z", + "modified": "2023-07-30T22:12:18.060Z", "headers": [], "params": [], "tests": [] }, { - "_id": "8c64ebf7-53be-4e57-aeb8-7166fa840bd7", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "25a2ca45-429a-45d0-b0ba-939f645308a8", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Update Entries", "url": "/v1/entries", "method": "PUT", "sortNum": 200000, - "created": "2023-07-13T20:04:56.925Z", - "modified": "2023-07-13T20:42:57.870Z", + "created": "2023-07-30T22:12:18.061Z", + "modified": "2023-07-30T22:12:18.061Z", "headers": [], "params": [], "body": { @@ -330,57 +337,63 @@ "tests": [] }, { - "_id": "df4cf36a-30f6-45fe-98bd-7716dcb13e48", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "60013d6e-8408-41a9-ac82-e11d982999ee", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Toggle Entry Bookmark", "url": "/v1/entries/184/bookmark", "method": "PUT", "sortNum": 210000, - "created": "2023-07-13T20:06:35.495Z", - "modified": "2023-07-13T20:42:23.966Z", + "created": "2023-07-30T22:12:18.062Z", + "modified": "2023-07-30T22:12:18.062Z", "headers": [], "params": [], "tests": [] }, { - "_id": "5ab1831b-ce3b-4f30-a713-cc7a7948ff7f", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "89d2f271-9df4-44e8-ab5c-e7848317a28a", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", - "name": "Toggle Entry Save", - "url": "/v1/entries/101/save", - "method": "PUT", + "name": "Save Entry", + "url": "/v1/entries/{entryID}/save", + "method": "POST", "sortNum": 215000, - "created": "2023-07-13T20:41:41.234Z", - "modified": "2023-07-13T20:50:55.001Z", + "created": "2023-07-30T22:12:18.083Z", + "modified": "2023-07-30T22:28:48.721Z", "headers": [], - "params": [], + "params": [ + { + "name": "entryID", + "value": "1", + "isPath": true + } + ], "tests": [] }, { - "_id": "cc24f030-934a-4ab7-b4dd-3d1ec611cbdb", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "6f19a8a9-d8db-485c-9a58-0b0b390b86da", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Categories", "url": "/v1/categories", "method": "GET", "sortNum": 220000, - "created": "2023-07-13T20:06:43.457Z", - "modified": "2023-07-13T20:24:03.603Z", + "created": "2023-07-30T22:12:18.063Z", + "modified": "2023-07-30T22:12:18.063Z", "headers": [], "params": [], "tests": [] }, { - "_id": "fc2188fb-06e5-4c51-8bda-6b74b88ee374", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "519cfed6-3205-4edf-9d38-0c35c4884653", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Create Category ", "url": "/v1/categories", "method": "POST", "sortNum": 230000, - "created": "2023-07-13T20:06:51.394Z", - "modified": "2023-07-13T20:23:49.243Z", + "created": "2023-07-30T22:12:18.064Z", + "modified": "2023-07-30T22:12:18.064Z", "headers": [], "params": [], "body": { @@ -391,15 +404,15 @@ "tests": [] }, { - "_id": "d48e1d75-7a60-421e-b7cd-510e322e1b52", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "61c6966c-bff8-49fa-95b4-9ec8346a1f27", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Update Category", "url": "/v1/categories/3", "method": "PUT", "sortNum": 240000, - "created": "2023-07-13T20:06:57.686Z", - "modified": "2023-07-13T20:24:54.935Z", + "created": "2023-07-30T22:12:18.065Z", + "modified": "2023-07-30T22:12:18.065Z", "headers": [], "params": [], "body": { @@ -410,71 +423,71 @@ "tests": [] }, { - "_id": "638c13a8-3761-4b2c-93b4-581edb2268b1", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "3496e223-ba67-419b-a51c-074226c2a14b", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Refresh Category Feeds", "url": "/v1/categories/3/refresh", "method": "PUT", "sortNum": 250000, - "created": "2023-07-13T20:07:04.246Z", - "modified": "2023-07-13T20:25:15.679Z", + "created": "2023-07-30T22:12:18.066Z", + "modified": "2023-07-30T22:12:18.066Z", "headers": [], "params": [], "tests": [] }, { - "_id": "5a806dba-cce7-4092-976f-e867e35acb09", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "93d5a1a8-9d99-4b13-b7d8-0e5480c32c88", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Delete Category", "url": "/v1/categories/3", "method": "DELETE", "sortNum": 260000, - "created": "2023-07-13T20:07:11.380Z", - "modified": "2023-07-13T20:25:37.067Z", + "created": "2023-07-30T22:12:18.067Z", + "modified": "2023-07-30T22:12:18.067Z", "headers": [], "params": [], "tests": [] }, { - "_id": "ad6fbc34-24ef-457a-a4d5-aced473325d5", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "479ab319-ae81-4e0d-a5ab-a3dfead17138", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Mark Category Entries as Read", "url": "/v1/categories/4/mark-all-as-read", "method": "PUT", "sortNum": 270000, - "created": "2023-07-13T20:07:59.762Z", - "modified": "2023-07-13T20:26:04.282Z", + "created": "2023-07-30T22:12:18.068Z", + "modified": "2023-07-30T22:12:18.068Z", "headers": [], "params": [], "tests": [] }, { - "_id": "042b06f0-89d9-4ec9-b8be-77b45ebb394c", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "e3f13a58-2215-4373-8d23-5473d17632b3", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "OPML Export", "url": "/v1/export", "method": "GET", "sortNum": 280000, - "created": "2023-07-13T20:08:15.300Z", - "modified": "2023-07-13T20:21:25.993Z", + "created": "2023-07-30T22:12:18.069Z", + "modified": "2023-07-30T22:12:18.069Z", "headers": [], "params": [], "tests": [] }, { - "_id": "26361a86-9a91-43bd-ace8-16ff47893796", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "05a903c4-9e64-4102-8b9d-45e3be5a57e1", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "OPML Import", "url": "/v1/import", "method": "POST", "sortNum": 290000, - "created": "2023-07-13T20:08:26.924Z", - "modified": "2023-07-13T20:22:44.084Z", + "created": "2023-07-30T22:12:18.070Z", + "modified": "2023-07-30T22:12:18.070Z", "headers": [], "params": [], "body": { @@ -485,15 +498,15 @@ "tests": [] }, { - "_id": "e8dcb639-45eb-4974-861e-0807abb09ee4", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "41e084e6-6211-4eec-8140-5c92693a9a73", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Create User", "url": "/v1/users", "method": "POST", "sortNum": 300000, - "created": "2023-07-13T20:08:38.772Z", - "modified": "2023-07-13T20:20:52.548Z", + "created": "2023-07-30T22:12:18.071Z", + "modified": "2023-07-30T22:12:18.071Z", "headers": [], "params": [], "body": { @@ -504,15 +517,15 @@ "tests": [] }, { - "_id": "4d0a52f1-d333-4185-b668-b09582f71aa3", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "c855a414-332c-49cd-902f-49d8e17ce7f9", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Update User", "url": "/v1/users/1", "method": "PUT", "sortNum": 310000, - "created": "2023-07-13T20:08:49.322Z", - "modified": "2023-07-13T20:20:14.840Z", + "created": "2023-07-30T22:12:18.072Z", + "modified": "2023-07-30T22:12:18.072Z", "headers": [], "params": [], "body": { @@ -523,121 +536,122 @@ "tests": [] }, { - "_id": "69d5eecd-7899-49bb-86b5-6e19b1c35017", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "d6f7e035-0d57-424e-b8bb-b50a22060fd0", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Current User", "url": "/v1/me", "method": "GET", "sortNum": 320000, - "created": "2023-07-13T20:08:57.866Z", - "modified": "2023-07-13T20:19:36.880Z", + "created": "2023-07-30T22:12:18.074Z", + "modified": "2023-07-30T22:12:18.074Z", "headers": [], "params": [], "tests": [] }, { - "_id": "6475a8be-598f-449e-8f60-008e419749d6", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "a75d5fc3-9f03-4feb-8963-62e7acc531f3", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get User", "url": "/v1/users/admin", "method": "GET", "sortNum": 330000, - "created": "2023-07-13T20:09:04.543Z", - "modified": "2023-07-13T20:19:23.898Z", + "created": "2023-07-30T22:12:18.075Z", + "modified": "2023-07-30T22:12:18.075Z", "headers": [], "params": [], "tests": [] }, { - "_id": "e6e867f3-6daf-4c97-987f-56154fa20087", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "a928c0f8-91c9-4e22-acbd-6224c8008559", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Get Users", "url": "/v1/users", "method": "GET", "sortNum": 340000, - "created": "2023-07-13T20:09:13.035Z", - "modified": "2023-07-13T20:18:37.740Z", + "created": "2023-07-30T22:12:18.076Z", + "modified": "2023-07-30T22:12:18.076Z", "headers": [], "params": [], "tests": [] }, { - "_id": "a7b276da-f45e-4b19-b3ae-5df347722612", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "01b3e426-0b52-4d9b-a1ee-7b757b8acdde", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Delete User", "url": "", "method": "GET", "sortNum": 350000, - "created": "2023-07-13T20:09:20.001Z", - "modified": "2023-07-13T20:09:20.001Z", + "created": "2023-07-30T22:12:18.077Z", + "modified": "2023-07-30T22:12:18.077Z", "headers": [] }, { - "_id": "32cb608b-787d-4119-9da0-b22e0c5d518e", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "c6a08dd0-d539-474e-a766-bbd5c7dfb644", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Mark User Entries as Read", "url": "", "method": "GET", "sortNum": 360000, - "created": "2023-07-13T20:09:28.638Z", - "modified": "2023-07-13T20:09:28.638Z", + "created": "2023-07-30T22:12:18.078Z", + "modified": "2023-07-30T22:12:18.078Z", "headers": [] }, { - "_id": "7e6a025b-3e6a-4847-8c62-65cd415d1c45", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "744fdd0f-ca5b-42cd-95e5-7e9ddb32ca36", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Fetch Read/Unread Counters", "url": "/v1/feeds/counters", "method": "GET", "sortNum": 370000, - "created": "2023-07-13T20:09:35.001Z", - "modified": "2023-07-13T20:18:17.473Z", + "created": "2023-07-30T22:12:18.079Z", + "modified": "2023-07-30T22:12:18.079Z", "headers": [], "params": [], "tests": [] }, { - "_id": "8ccff897-d206-42e7-ac5b-436c17da5cea", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "f7f48bc4-d18e-42cf-9baa-b9e623245f5e", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Healthcheck", "url": "/healthcheck", "method": "GET", "sortNum": 380000, - "created": "2023-07-13T20:09:45.003Z", - "modified": "2023-07-13T20:18:09.635Z", + "created": "2023-07-30T22:12:18.080Z", + "modified": "2023-07-30T22:12:18.080Z", "headers": [], "params": [], "tests": [] }, { - "_id": "7241fce0-0496-44a0-8f94-53bbe0498ce9", - "colId": "99c8ee49-0c9a-4243-9f35-07de6bf2df68", + "_id": "27b002a3-1322-4745-8f66-00b69f10be4a", + "colId": "ed8ec848-afd7-40a2-bef6-d177439a9263", "containerId": "", "name": "Version", "url": "/version", "method": "GET", "sortNum": 390000, - "created": "2023-07-13T20:09:53.633Z", - "modified": "2023-07-13T20:17:59.749Z", + "created": "2023-07-30T22:12:18.081Z", + "modified": "2023-07-30T22:12:18.081Z", "headers": [], "params": [], "tests": [] } ], "settings": { - "headers": [ - { - "name": "X-Auth-Token", - "value": "W9QztpZfQYe0fPfrfZO-34fGWZ5DRInK5INBmmI2ENU=" + "auth": { + "type": "basic", + "basic": { + "username": "admin", + "password": "test123" } - ], + }, "options": { "baseUrl": "http://localhost:8080" } diff --git a/Makefile b/Makefile index 54862972..bb84153b 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ windows-x86: @ GOOS=windows GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go run: - @ LOG_DATE_TIME=1 DEBUG=1 RUN_MIGRATIONS=1 go run main.go + @ LOG_DATE_TIME=1 DEBUG=1 RUN_MIGRATIONS=1 CREATE_ADMIN=1 ADMIN_USERNAME=admin ADMIN_PASSWORD=test123 go run main.go clean: @ rm -f $(APP)-* $(APP) $(APP)*.rpm $(APP)*.deb diff --git a/api/api.go b/api/api.go index 890dec0f..54fa0ad5 100644 --- a/api/api.go +++ b/api/api.go @@ -64,6 +64,6 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) { sr.HandleFunc("/entries", handler.setEntryStatus).Methods(http.MethodPut) sr.HandleFunc("/entries/{entryID}", handler.getEntry).Methods(http.MethodGet) sr.HandleFunc("/entries/{entryID}/bookmark", handler.toggleBookmark).Methods(http.MethodPut) - sr.HandleFunc("/entries/{entryID}/save", handler.saveEntry).Methods(http.MethodPut) + sr.HandleFunc("/entries/{entryID}/save", handler.saveEntry).Methods(http.MethodPost) sr.HandleFunc("/entries/{entryID}/fetch-content", handler.fetchContent).Methods(http.MethodGet) } diff --git a/api/entry.go b/api/entry.go index 9b911b44..820a5306 100644 --- a/api/entry.go +++ b/api/entry.go @@ -127,13 +127,13 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int userID := request.UserID(r) categoryID = request.QueryInt64Param(r, "category_id", categoryID) if categoryID > 0 && !h.store.CategoryIDExists(userID, categoryID) { - json.BadRequest(w, r, errors.New("Invalid category ID")) + json.BadRequest(w, r, errors.New("invalid category ID")) return } feedID = request.QueryInt64Param(r, "feed_id", feedID) if feedID > 0 && !h.store.FeedExists(userID, feedID) { - json.BadRequest(w, r, errors.New("Invalid feed ID")) + json.BadRequest(w, r, errors.New("invalid feed ID")) return } @@ -203,11 +203,12 @@ func (h *handler) saveEntry(w http.ResponseWriter, r *http.Request) { builder := h.store.NewEntryQueryBuilder(request.UserID(r)) builder.WithEntryID(entryID) builder.WithoutStatus(model.EntryStatusRemoved) - // check if user has save entry enabled + if !h.store.HasSaveEntry(request.UserID(r)) { - json.BadRequest(w, r, errors.New("at least one enabled integration is required")) + json.BadRequest(w, r, errors.New("no third-party integration enabled")) return } + entry, err := builder.GetEntry() if err != nil { json.ServerError(w, r, err) @@ -225,11 +226,9 @@ func (h *handler) saveEntry(w http.ResponseWriter, r *http.Request) { return } - go func() { - integration.SendEntry(entry, settings) - }() + go integration.SendEntry(entry, settings) - json.NoContent(w, r) + json.Accepted(w, r) } func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) { diff --git a/client/client.go b/client/client.go index 67d0fbd0..892fa5fd 100644 --- a/client/client.go +++ b/client/client.go @@ -39,8 +39,7 @@ func (c *Client) Me() (*User, error) { defer body.Close() var user *User - decoder := json.NewDecoder(body) - if err := decoder.Decode(&user); err != nil { + if err := json.NewDecoder(body).Decode(&user); err != nil { return nil, fmt.Errorf("miniflux: json error (%v)", err) } @@ -56,8 +55,7 @@ func (c *Client) Users() (Users, error) { defer body.Close() var users Users - decoder := json.NewDecoder(body) - if err := decoder.Decode(&users); err != nil { + if err := json.NewDecoder(body).Decode(&users); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -73,8 +71,7 @@ func (c *Client) UserByID(userID int64) (*User, error) { defer body.Close() var user User - decoder := json.NewDecoder(body) - if err := decoder.Decode(&user); err != nil { + if err := json.NewDecoder(body).Decode(&user); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -90,8 +87,7 @@ func (c *Client) UserByUsername(username string) (*User, error) { defer body.Close() var user User - decoder := json.NewDecoder(body) - if err := decoder.Decode(&user); err != nil { + if err := json.NewDecoder(body).Decode(&user); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -111,8 +107,7 @@ func (c *Client) CreateUser(username, password string, isAdmin bool) (*User, err defer body.Close() var user *User - decoder := json.NewDecoder(body) - if err := decoder.Decode(&user); err != nil { + if err := json.NewDecoder(body).Decode(&user); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -128,8 +123,7 @@ func (c *Client) UpdateUser(userID int64, userChanges *UserModificationRequest) defer body.Close() var u *User - decoder := json.NewDecoder(body) - if err := decoder.Decode(&u); err != nil { + if err := json.NewDecoder(body).Decode(&u); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -156,8 +150,7 @@ func (c *Client) Discover(url string) (Subscriptions, error) { defer body.Close() var subscriptions Subscriptions - decoder := json.NewDecoder(body) - if err := decoder.Decode(&subscriptions); err != nil { + if err := json.NewDecoder(body).Decode(&subscriptions); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -173,8 +166,7 @@ func (c *Client) Categories() (Categories, error) { defer body.Close() var categories Categories - decoder := json.NewDecoder(body) - if err := decoder.Decode(&categories); err != nil { + if err := json.NewDecoder(body).Decode(&categories); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -192,8 +184,7 @@ func (c *Client) CreateCategory(title string) (*Category, error) { defer body.Close() var category *Category - decoder := json.NewDecoder(body) - if err := decoder.Decode(&category); err != nil { + if err := json.NewDecoder(body).Decode(&category); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -211,8 +202,7 @@ func (c *Client) UpdateCategory(categoryID int64, title string) (*Category, erro defer body.Close() var category *Category - decoder := json.NewDecoder(body) - if err := decoder.Decode(&category); err != nil { + if err := json.NewDecoder(body).Decode(&category); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -234,8 +224,7 @@ func (c *Client) CategoryFeeds(categoryID int64) (Feeds, error) { defer body.Close() var feeds Feeds - decoder := json.NewDecoder(body) - if err := decoder.Decode(&feeds); err != nil { + if err := json.NewDecoder(body).Decode(&feeds); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -262,8 +251,7 @@ func (c *Client) Feeds() (Feeds, error) { defer body.Close() var feeds Feeds - decoder := json.NewDecoder(body) - if err := decoder.Decode(&feeds); err != nil { + if err := json.NewDecoder(body).Decode(&feeds); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -301,8 +289,7 @@ func (c *Client) Feed(feedID int64) (*Feed, error) { defer body.Close() var feed *Feed - decoder := json.NewDecoder(body) - if err := decoder.Decode(&feed); err != nil { + if err := json.NewDecoder(body).Decode(&feed); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -322,8 +309,7 @@ func (c *Client) CreateFeed(feedCreationRequest *FeedCreationRequest) (int64, er } var r result - decoder := json.NewDecoder(body) - if err := decoder.Decode(&r); err != nil { + if err := json.NewDecoder(body).Decode(&r); err != nil { return 0, fmt.Errorf("miniflux: response error (%v)", err) } @@ -378,8 +364,7 @@ func (c *Client) FeedIcon(feedID int64) (*FeedIcon, error) { defer body.Close() var feedIcon *FeedIcon - decoder := json.NewDecoder(body) - if err := decoder.Decode(&feedIcon); err != nil { + if err := json.NewDecoder(body).Decode(&feedIcon); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -395,8 +380,7 @@ func (c *Client) FeedEntry(feedID, entryID int64) (*Entry, error) { defer body.Close() var entry *Entry - decoder := json.NewDecoder(body) - if err := decoder.Decode(&entry); err != nil { + if err := json.NewDecoder(body).Decode(&entry); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -412,8 +396,7 @@ func (c *Client) CategoryEntry(categoryID, entryID int64) (*Entry, error) { defer body.Close() var entry *Entry - decoder := json.NewDecoder(body) - if err := decoder.Decode(&entry); err != nil { + if err := json.NewDecoder(body).Decode(&entry); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -429,8 +412,7 @@ func (c *Client) Entry(entryID int64) (*Entry, error) { defer body.Close() var entry *Entry - decoder := json.NewDecoder(body) - if err := decoder.Decode(&entry); err != nil { + if err := json.NewDecoder(body).Decode(&entry); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -448,8 +430,7 @@ func (c *Client) Entries(filter *Filter) (*EntryResultSet, error) { defer body.Close() var result EntryResultSet - decoder := json.NewDecoder(body) - if err := decoder.Decode(&result); err != nil { + if err := json.NewDecoder(body).Decode(&result); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -467,8 +448,7 @@ func (c *Client) FeedEntries(feedID int64, filter *Filter) (*EntryResultSet, err defer body.Close() var result EntryResultSet - decoder := json.NewDecoder(body) - if err := decoder.Decode(&result); err != nil { + if err := json.NewDecoder(body).Decode(&result); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -486,8 +466,7 @@ func (c *Client) CategoryEntries(categoryID int64, filter *Filter) (*EntryResult defer body.Close() var result EntryResultSet - decoder := json.NewDecoder(body) - if err := decoder.Decode(&result); err != nil { + if err := json.NewDecoder(body).Decode(&result); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } @@ -511,6 +490,12 @@ func (c *Client) ToggleBookmark(entryID int64) error { return err } +// SaveEntry sends an entry to a third-party service. +func (c *Client) SaveEntry(entryID int64) error { + _, err := c.request.Post(fmt.Sprintf("/v1/entries/%d/save", entryID), nil) + return err +} + // FetchCounters func (c *Client) FetchCounters() (*FeedCounters, error) { body, err := c.request.Get("/v1/feeds/counters") @@ -520,8 +505,7 @@ func (c *Client) FetchCounters() (*FeedCounters, error) { defer body.Close() var result FeedCounters - decoder := json.NewDecoder(body) - if err := decoder.Decode(&result); err != nil { + if err := json.NewDecoder(body).Decode(&result); err != nil { return nil, fmt.Errorf("miniflux: response error (%v)", err) } diff --git a/http/response/json/json.go b/http/response/json/json.go index 3033045d..17eca55a 100644 --- a/http/response/json/json.go +++ b/http/response/json/json.go @@ -39,6 +39,13 @@ func NoContent(w http.ResponseWriter, r *http.Request) { builder.Write() } +func Accepted(w http.ResponseWriter, r *http.Request) { + builder := response.New(w, r) + builder.WithStatus(http.StatusAccepted) + builder.WithHeader("Content-Type", contentTypeHeader) + builder.Write() +} + // ServerError sends an internal error to the client. func ServerError(w http.ResponseWriter, r *http.Request, err error) { logger.Error("[HTTP:Internal Server Error] %s => %v", r.URL, err) @@ -68,7 +75,7 @@ func Unauthorized(w http.ResponseWriter, r *http.Request) { builder := response.New(w, r) builder.WithStatus(http.StatusUnauthorized) builder.WithHeader("Content-Type", contentTypeHeader) - builder.WithBody(toJSONError(errors.New("Access Unauthorized"))) + builder.WithBody(toJSONError(errors.New("access unauthorized"))) builder.Write() } @@ -79,7 +86,7 @@ func Forbidden(w http.ResponseWriter, r *http.Request) { builder := response.New(w, r) builder.WithStatus(http.StatusForbidden) builder.WithHeader("Content-Type", contentTypeHeader) - builder.WithBody(toJSONError(errors.New("Access Forbidden"))) + builder.WithBody(toJSONError(errors.New("access forbidden"))) builder.Write() } @@ -90,7 +97,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) { builder := response.New(w, r) builder.WithStatus(http.StatusNotFound) builder.WithHeader("Content-Type", contentTypeHeader) - builder.WithBody(toJSONError(errors.New("Resource Not Found"))) + builder.WithBody(toJSONError(errors.New("resource not found"))) builder.Write() } diff --git a/http/response/json/json_test.go b/http/response/json/json_test.go index 1f3e6f19..43f72713 100644 --- a/http/response/json/json_test.go +++ b/http/response/json/json_test.go @@ -199,7 +199,7 @@ func TestUnauthorizedResponse(t *testing.T) { t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode) } - expectedBody := `{"error_message":"Access Unauthorized"}` + expectedBody := `{"error_message":"access unauthorized"}` actualBody := w.Body.String() if actualBody != expectedBody { t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody) @@ -232,7 +232,7 @@ func TestForbiddenResponse(t *testing.T) { t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode) } - expectedBody := `{"error_message":"Access Forbidden"}` + expectedBody := `{"error_message":"access forbidden"}` actualBody := w.Body.String() if actualBody != expectedBody { t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody) @@ -265,7 +265,7 @@ func TestNotFoundResponse(t *testing.T) { t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode) } - expectedBody := `{"error_message":"Resource Not Found"}` + expectedBody := `{"error_message":"resource not found"}` actualBody := w.Body.String() if actualBody != expectedBody { t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody)