diff --git a/postman/reactredux.postman_collection.json b/postman/reactredux.postman_collection.json index ed15190..f735f1c 100644 --- a/postman/reactredux.postman_collection.json +++ b/postman/reactredux.postman_collection.json @@ -25,16 +25,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/Content/404c8232-9048-4519-bfba-6e78dc7005ca?locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/Content/{{siteId}}?locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "Content", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -68,16 +65,14 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItem/404c8232-9048-4519-bfba-6e78dc7005ca/e154e33f-3cc7-468d-bb66-e0390ddb9ae0", - "protocol": "https", + "raw": "{{baseUrl}}//CategoryItem/{{siteId}}/e154e33f-3cc7-468d-bb66-e0390ddb9ae0", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", + "", "CategoryItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "e154e33f-3cc7-468d-bb66-e0390ddb9ae0" ] } @@ -101,16 +96,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItem/404c8232-9048-4519-bfba-6e78dc7005ca?slug=default", - "protocol": "https", + "raw": "{{baseUrl}}/CategoryItem/{{siteId}}?slug=default", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "CategoryItem", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -143,16 +135,14 @@ "raw": "{\r\n \"l10n\": [\r\n {\r\n \"locale\": \"\",\r\n \"slug\": \"guides\",\r\n \"text\": \"Guides\"\r\n }\r\n ]\r\n}" }, "url": { - "raw": "https://localhost:7151/api/CategoryItem/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}//CategoryItem/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", + "", "CategoryItem", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -179,16 +169,14 @@ "raw": "{\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"slug\": \"guides\",\r\n \"text\": \"Guides\"\r\n },\r\n {\r\n \"locale\": \"it-IT\",\r\n \"slug\": \"guide\",\r\n \"text\": \"Guide\"\r\n }\r\n ]\r\n}" }, "url": { - "raw": "https://localhost:7151/api/CategoryItem/404c8232-9048-4519-bfba-6e78dc7005ca/2c50f4de-70f2-4414-aabc-7a0d2eb0e203", - "protocol": "https", + "raw": "{{baseUrl}}//CategoryItem/{{siteId}}/2c50f4de-70f2-4414-aabc-7a0d2eb0e203", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", + "", "CategoryItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "2c50f4de-70f2-4414-aabc-7a0d2eb0e203" ] } @@ -212,17 +200,14 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItem/404c8232-9048-4519-bfba-6e78dc7005ca/2c50f4de-70f2-4414-aabc-7a0d2eb0e203", - "protocol": "https", + "raw": "{{baseUrl}}/CategoryItem/{{siteId}}/e154e33f-3cc7-468d-bb66-e0390ddb9ae0", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "CategoryItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", - "2c50f4de-70f2-4414-aabc-7a0d2eb0e203" + "{{siteId}}", + "e154e33f-3cc7-468d-bb66-e0390ddb9ae0" ] } }, @@ -250,16 +235,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItems/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}/CategoryItems/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "CategoryItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -282,16 +264,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItems/404c8232-9048-4519-bfba-6e78dc7005ca?locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/CategoryItems/{{siteId}}?locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "CategoryItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -320,16 +299,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/CategoryItems/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}/CategoryItems/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "CategoryItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -341,78 +317,7 @@ "name": "ShopItem", "item": [ { - "name": "01-Get", - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "default" - }, - { - "key": "Accept", - "value": "application/json", - "type": "default" - } - ], - "url": { - "raw": "https://localhost:7151/api/ShopItem/404c8232-9048-4519-bfba-6e78dc7005ca/SKU-01", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "7151", - "path": [ - "api", - "ShopItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", - "SKU-01" - ] - } - }, - "response": [] - }, - { - "name": "02-GetSlug", - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "default" - }, - { - "key": "Accept", - "value": "application/json", - "type": "default" - } - ], - "url": { - "raw": "https://localhost:7151/api/ShopItem/404c8232-9048-4519-bfba-6e78dc7005ca?slug=shop-catalog-item-01", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "7151", - "path": [ - "api", - "ShopItem", - "404c8232-9048-4519-bfba-6e78dc7005ca" - ], - "query": [ - { - "key": "slug", - "value": "shop-catalog-item-01" - } - ] - } - }, - "response": [] - }, - { - "name": "03-Post", + "name": "01-Post", "request": { "method": "POST", "header": [ @@ -429,19 +334,16 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"l10n\":[\r\n {\r\n \"locale\":\"en-US\",\r\n \"slug\":\"shop-catalog-item-05\",\r\n \"description\": \"Descritpion...\",\r\n \"title\":\"Shop item title\",\r\n \"shortText\":\"Shor text...\",\r\n \"text\":\"Text...\",\r\n \"contentType\": \"HTML\",\r\n \"badges\":[\r\n \"sale\"\r\n ]\r\n }\r\n ],\r\n \r\n \"tags\":[\r\n \"react\",\r\n \"redux\",\r\n \"webapi\"\r\n ],\r\n \"categories\":[\r\n \"e154e33f-3cc7-468d-bb66-e0390ddb9ae0\"\r\n ],\r\n \"brandName\":\"Mongodb Brand & Name\",\r\n \"rating\":4.5,\r\n \"price\":20,\r\n \"newPrice\":10,\r\n \"quantity\":100\r\n}" + "raw": "{\r\n \"siteId\": \"404c8232-9048-4519-bfba-6e78dc7005ca\",\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"slug\": \"shop-catalog-item-05\",\r\n \"description\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit.\",\r\n \"title\": \"Shop item title\",\r\n \"shortText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...\",\r\n \"text\": \"

Lorem ipsum, dolor sit amet consectetur adipisicing elit.

\",\r\n \"textFormat\": \"HTML\",\r\n \"plainText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit.\",\r\n \"badges\": [\r\n \"sale\"\r\n ]\r\n }\r\n ],\r\n\t\"mediaAttachments\": [\r\n\t {\r\n\t\t\"src\": \"api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692\",\r\n\t\t\"mediaType\": \"image\",\r\n\t\t\"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"alt\": \"...\",\r\n\t\t\t\"target\": \"/title-image\",\r\n\t\t\t\"title\": \"Title image\",\r\n\t\t\t\"description\": \"Title image description.\"\r\n\t }\r\n ]\r\n\t }\r\n\t],\r\n \"author\": \"fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60\",\r\n \"created\": {\r\n \"$date\": \"2022-01-01T00:00:00.000Z\"\r\n },\r\n \"tags\": [\r\n \"react\",\r\n \"redux\",\r\n \"webapi\"\r\n ],\r\n \"brandName\": \"Mongodb Brand & Name\",\r\n \"sku\": \"SKU-05\",\r\n \"rating\": 4.5,\r\n \"price\": 20,\r\n \"newPrice\": 10,\r\n \"quantity\": 100\r\n }" }, "url": { - "raw": "https://localhost:7151/api/ShopItem/404c8232-9048-4519-bfba-6e78dc7005ca/SKU-05", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItem/{{siteId}}/SKU-05", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "SKU-05" ] } @@ -449,7 +351,74 @@ "response": [] }, { - "name": "04-Put", + "name": "02-Get", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "url": { + "raw": "{{baseUrl}}//ShopItem/{{siteId}}/SKU-05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "", + "ShopItem", + "{{siteId}}", + "SKU-05" + ] + } + }, + "response": [] + }, + { + "name": "03-GetSlug", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "url": { + "raw": "{{baseUrl}}/ShopItem/{{siteId}}?slug=shop-catalog-item-05", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "", + "ShopItem", + "{{siteId}}" + ], + "query": [ + { + "key": "slug", + "value": "shop-catalog-item-05" + } + ] + } + }, + "response": [] + }, + { + "name": "05-Put", "request": { "method": "PUT", "header": [ @@ -466,19 +435,16 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"l10n\":[\r\n {\r\n \"locale\":\"en-US\",\r\n \"slug\":\"shop-catalog-item-05\",\r\n \"description\": \"New Descritpion...\",\r\n \"title\":\"Shop item title\",\r\n \"shortText\":\"New Shor text...\",\r\n \"text\":\"New Text...\",\r\n \"contentType\": \"HTML\",\r\n \"badges\":[\r\n \"sale\"\r\n ]\r\n }\r\n ],\r\n \r\n \"tags\":[\r\n \"react\",\r\n \"redux\",\r\n \"webapi\"\r\n ],\r\n \"categories\":[\r\n \"e154e33f-3cc7-468d-bb66-e0390ddb9ae0\"\r\n ],\r\n \"brandName\":\"Mongodb Brand & Name\",\r\n \"rating\":4.5,\r\n \"price\":20,\r\n \"newPrice\":10,\r\n \"quantity\":100\r\n}" + "raw": "{\r\n \"siteId\": \"404c8232-9048-4519-bfba-6e78dc7005ca\",\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"slug\": \"shop-catalog-item-05\",\r\n \"description\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit.\",\r\n \"title\": \"Shop item title\",\r\n \"shortText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...\",\r\n \"text\": \"

Lorem ipsum, dolor sit amet consectetur adipisicing elit.

\",\r\n \"textFormat\": \"HTML\",\r\n \"plainText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit.\",\r\n \"badges\": [\r\n \"sale\"\r\n ]\r\n }\r\n ],\r\n\t\"mediaAttachments\": [\r\n\t {\r\n\t\t\"src\": \"api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692\",\r\n\t\t\"mediaType\": \"image\",\r\n\t\t\"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"alt\": \"...\",\r\n\t\t\t\"target\": \"/title-image\",\r\n\t\t\t\"title\": \"Title image\",\r\n\t\t\t\"description\": \"Title image description.\"\r\n\t }\r\n ]\r\n\t }\r\n\t],\r\n \"author\": \"fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60\",\r\n \"created\": {\r\n \"$date\": \"2022-01-01T00:00:00.000Z\"\r\n },\r\n \"tags\": [\r\n \"react\",\r\n \"redux\",\r\n \"webapi\"\r\n ],\r\n \"categories\": [\r\n \"e154e33f-3cc7-468d-bb66-e0390ddb9ae0\"\r\n ],\r\n \"brandName\": \"Mongodb Brand & Name\",\r\n \"sku\": \"SKU-05\",\r\n \"rating\": 4.5,\r\n \"price\": 20,\r\n \"newPrice\": 10,\r\n \"quantity\": 100\r\n }" }, "url": { - "raw": "https://localhost:7151/api/ShopItem/404c8232-9048-4519-bfba-6e78dc7005ca/SKU-05", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItem/{{siteId}}/SKU-05", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "SKU-05" ] } @@ -486,7 +452,7 @@ "response": [] }, { - "name": "05-Delete", + "name": "06-Delete", "request": { "method": "DELETE", "header": [ @@ -502,16 +468,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopItem/404c8232-9048-4519-bfba-6e78dc7005ca/SKU-05", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItem/{{siteId}}/SKU-05", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "SKU-05" ] } @@ -540,16 +503,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopItems/404c8232-9048-4519-bfba-6e78dc7005ca?currentPage=1&itemsPerPage=4", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItems/{{siteId}}?currentPage=1&itemsPerPage=4", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -582,16 +542,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopItems/404c8232-9048-4519-bfba-6e78dc7005ca?currentPage=2&itemsPerPage=2&locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItems/{{siteId}}?currentPage=2&itemsPerPage=2&locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -628,16 +585,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopItems/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}/ShopItems/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -665,16 +619,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04?locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/ShopCartItem/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04?locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopCartItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "SKU-04" ], @@ -709,16 +660,14 @@ "raw": "{\r\n \"quantity\": 1\r\n}" }, "url": { - "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-05", - "protocol": "https", + "raw": "{{baseUrl}}//ShopCartItem/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-05", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", + "", "ShopCartItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "SKU-05" ] @@ -747,16 +696,13 @@ "raw": "{\r\n \"quantity\": 5\r\n}" }, "url": { - "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", - "protocol": "https", + "raw": "{{baseUrl}}/ShopCartItem/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopCartItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "SKU-04" ] @@ -781,16 +727,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", - "protocol": "https", + "raw": "{{baseUrl}}/ShopCartItem/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopCartItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "SKU-04" ] @@ -820,16 +763,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopCartItems/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60?locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/ShopCartItems/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60?locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopCartItems", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" ], "query": [ @@ -859,16 +799,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopCartItems/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", - "protocol": "https", + "raw": "{{baseUrl}}/ShopCartItems/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "ShopCartItems", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" ] } @@ -897,16 +834,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItem/404c8232-9048-4519-bfba-6e78dc7005ca/11f2f5f8-1270-4640-b082-c2e7ea8e60b4", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItem/{{siteId}}/11f2f5f8-1270-4640-b082-c2e7ea8e60b4", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "11f2f5f8-1270-4640-b082-c2e7ea8e60b4" ] } @@ -930,16 +864,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItem/404c8232-9048-4519-bfba-6e78dc7005ca?slug=privacy-terms-and-conditions", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItem/{{siteId}}?slug=privacy-terms-and-conditions", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItem", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -972,16 +903,13 @@ "raw": "{\r\n\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"slug\": \"hello-world\",\r\n \"description\": \"Hello world description\",\r\n \"title\": \"Hello world title\",\r\n \"shortText\": \"Hello world short text\",\r\n \"text\": \"

Hello World

\",\r\n \"contentType\": \"HTML\",\r\n \"badges\": [\r\n \"post\"\r\n ]\r\n }\r\n ],\r\n \"images\": [\r\n {\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"alt\": \"...\"\r\n },\r\n {\r\n \"locale\": \"it-IT\",\r\n \"alt\": \"...\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"tags\": [\r\n \"privacy\",\r\n \"terms\"\r\n ],\r\n \"categories\": [\r\n \"e154e33f-3cc7-468d-bb66-e0390ddb9ae0\" \r\n ],\r\n \"familyFriendly\": true\r\n}" }, "url": { - "raw": "https://localhost:7151/api/BlogItem/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItem/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItem", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -1008,16 +936,13 @@ "raw": "{\r\n\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"slug\": \"hello-world\",\r\n \"description\": \"Hello world description\",\r\n \"title\": \"Hello world title\",\r\n \"shortText\": \"Hello world short text\",\r\n \"text\": \"

New Hello World

\",\r\n \"contentType\": \"HTML\",\r\n \"badges\": [\r\n \"post\"\r\n ]\r\n }\r\n ],\r\n \"images\": [\r\n {\r\n \"l10n\": [\r\n {\r\n \"locale\": \"en-US\",\r\n \"alt\": \"...\"\r\n },\r\n {\r\n \"locale\": \"it-IT\",\r\n \"alt\": \"...\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"tags\": [\r\n \"privacy\",\r\n \"terms\"\r\n ],\r\n \"categories\": [\r\n \"e154e33f-3cc7-468d-bb66-e0390ddb9ae0\" \r\n ],\r\n \"familyFriendly\": true\r\n}" }, "url": { - "raw": "https://localhost:7151/api/BlogItem/404c8232-9048-4519-bfba-6e78dc7005ca/94feda90-ddf6-4717-8879-9c7139e7ff30", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItem/{{siteId}}/94feda90-ddf6-4717-8879-9c7139e7ff30", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "94feda90-ddf6-4717-8879-9c7139e7ff30" ] } @@ -1041,16 +966,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItem/404c8232-9048-4519-bfba-6e78dc7005ca/94feda90-ddf6-4717-8879-9c7139e7ff30", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItem/{{siteId}}/94feda90-ddf6-4717-8879-9c7139e7ff30", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItem", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "94feda90-ddf6-4717-8879-9c7139e7ff30" ] } @@ -1079,16 +1001,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItems/404c8232-9048-4519-bfba-6e78dc7005ca?currentPage=2&itemsPerPage=2", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItems/{{siteId}}?currentPage=2&itemsPerPage=2", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -1121,16 +1040,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItems/404c8232-9048-4519-bfba-6e78dc7005ca?currentPage=2&itemsPerPage=2&locale=en-US", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItems/{{siteId}}?currentPage=2&itemsPerPage=2&locale=en-US", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ], "query": [ { @@ -1167,16 +1083,13 @@ } ], "url": { - "raw": "https://localhost:7151/api/BlogItems/404c8232-9048-4519-bfba-6e78dc7005ca", - "protocol": "https", + "raw": "{{baseUrl}}/BlogItems/{{siteId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "BlogItems", - "404c8232-9048-4519-bfba-6e78dc7005ca" + "{{siteId}}" ] } }, @@ -1204,16 +1117,84 @@ } ], "url": { - "raw": "https://localhost:7151/api/File/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/3930ff55-67e1-4763-be59-37407f91e0a9", - "protocol": "https", + "raw": "{{baseUrl}}/File/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/4f163ea9-1786-4192-8efa-3b8ea9ca88fa", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "File", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "4f163ea9-1786-4192-8efa-3b8ea9ca88fa" + ] + } + }, + "response": [] + }, + { + "name": "02-Post", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/ecmascript", + "type": "default" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "type": "file", + "src": "/C:/Users/maksym/Desktop/Arpeggios.gp" + } + ] + }, + "url": { + "raw": "{{baseUrl}}/File/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "File", + "{{siteId}}", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" + ] + } + }, + "response": [] + }, + { + "name": "04-Delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "url": { + "raw": "{{baseUrl}}/File/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/3930ff55-67e1-4763-be59-37407f91e0a9", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "File", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "3930ff55-67e1-4763-be59-37407f91e0a9" ] @@ -1254,16 +1235,13 @@ ] }, "url": { - "raw": "https://localhost:7151/api/Files/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", - "protocol": "https", + "raw": "{{baseUrl}}/Files/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "Files", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" ] } @@ -1298,16 +1276,13 @@ ] }, "url": { - "raw": "https://localhost:7151/api/Files/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", - "protocol": "https", + "raw": "{{baseUrl}}/Files/{{siteId}}/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "7151", "path": [ - "api", "Files", - "404c8232-9048-4519-bfba-6e78dc7005ca", + "{{siteId}}", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" ] } @@ -1315,6 +1290,63 @@ "response": [] } ] + }, + { + "name": "Image", + "item": [ + { + "name": "01-Get", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/Image/{{siteId}}/450x300/55ecc564-c086-4e77-a8b2-ef32c2a8c280", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "Image", + "{{siteId}}", + "450x300", + "55ecc564-c086-4e77-a8b2-ef32c2a8c280" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "https://localhost:7151/api", + "type": "default" + }, + { + "key": "siteId", + "value": "404c8232-9048-4519-bfba-6e78dc7005ca", + "type": "default" } ] } \ No newline at end of file diff --git a/webapi/DataProviders/Abstractions/BucketDataProviderBase.cs b/webapi/DataProviders/Abstractions/BucketDataProviderBase.cs index 2c11b98..4c0c208 100644 --- a/webapi/DataProviders/Abstractions/BucketDataProviderBase.cs +++ b/webapi/DataProviders/Abstractions/BucketDataProviderBase.cs @@ -41,11 +41,11 @@ namespace DataProviders.Abstractions { #endregion #region Download - private protected (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId, string bucketName) => - DownloadAsync(siteId, userId, fileId, bucketName).Result; + private protected (List?, IDomainResult) Download(FilterDefinition filter, string bucketName) => + DownloadAsync(filter, bucketName).Result; - private protected Task<(BucketFile?, IDomainResult)> DownloadAsync(Guid siteId, Guid userId, Guid fileId, string bucketName) => - DownloadAsyncCore(siteId, userId, fileId, bucketName); + private protected Task<(List?, IDomainResult)> DownloadAsync(FilterDefinition filter, string bucketName) => + DownloadAsyncCore(filter, bucketName); #endregion #region Delete @@ -115,49 +115,49 @@ namespace DataProviders.Abstractions { } } - private async Task<(BucketFile?, IDomainResult)> DownloadAsyncCore(Guid siteId, Guid userId, Guid fileId, string bucketName) { + private async Task<(List?, IDomainResult)> DownloadAsyncCore(FilterDefinition filter, string bucketName) { try { - var filter = Builders.Filter.And( - Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"), - Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}"), - Builders.Filter.Eq(x => x.Filename, $"{fileId}") - ); - var sort = Builders.Sort.Descending(x => x.UploadDateTime); var bucket = CreateBucket(bucketName); using var cursor = await bucket.FindAsync(filter, new GridFSFindOptions { - Limit = 1, Sort = sort, }); + var result = new List(); + // fileInfo either has the matching file information or is null - var fileInfo = (await cursor.ToListAsync()).FirstOrDefault(); - if (fileInfo == null) - return IDomainResult.NotFound(); + foreach (var fileInfo in await cursor.ToListAsync()) { + if (fileInfo == null) + return IDomainResult.NotFound?>(); - var fileName = fileInfo.Metadata["fileName"].ToString() ?? ""; - if (fileName == null) - return IDomainResult.Failed(); + var fileName = fileInfo.Metadata["fileName"].ToString() ?? ""; + if (fileName == null) + return IDomainResult.Failed?>(); - var contentType = fileInfo.Metadata["contentType"].ToString() ?? ""; - if (contentType == null) - return IDomainResult.Failed(); + var contentType = fileInfo.Metadata["contentType"].ToString() ?? ""; + if (contentType == null) + return IDomainResult.Failed?>(); - var bytes = await bucket.DownloadAsBytesByNameAsync($"{fileId}", new GridFSDownloadByNameOptions { - Revision = -1 - }); + var bytes = await bucket.DownloadAsBytesByNameAsync($"{fileInfo.Filename}", new GridFSDownloadByNameOptions { + Revision = -1 + }); - if(bytes == null) - return IDomainResult.Failed(); + if (bytes == null) + return IDomainResult.Failed?>(); - return IDomainResult.Success(new BucketFile(fileName, bytes, contentType)); + result.Add(new BucketFile(fileName, bytes, contentType)); + } + + return result.Count > 0 + ? IDomainResult.Success(result) + : IDomainResult.NotFound?>(); } catch (Exception ex) { _logger.LogError(ex, "Bucket data provider error"); - return IDomainResult.Failed(); + return IDomainResult.Failed?>(); } } diff --git a/webapi/DataProviders/Abstractions/SpecificBucketDataProviderBase.cs b/webapi/DataProviders/Abstractions/SpecificBucketDataProviderBase.cs index 417bd44..dc282b2 100644 --- a/webapi/DataProviders/Abstractions/SpecificBucketDataProviderBase.cs +++ b/webapi/DataProviders/Abstractions/SpecificBucketDataProviderBase.cs @@ -5,6 +5,7 @@ using DomainResults.Common; using MongoDB.Driver; using DataProviders.Abstractions; +using MongoDB.Driver.GridFS; namespace DataProviders.Buckets { @@ -46,14 +47,28 @@ namespace DataProviders.Buckets { /// public (List?, IDomainResult) UploadMany(Guid siteId, Guid userId, List files) => UploadMany(siteId, userId, files, _bucketName); + /// /// /// /// - /// /// /// - public (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId) => Download(siteId, userId, fileId, _bucketName); + public (BucketFile?, IDomainResult) Download(Guid siteId, Guid fileId) { + var filter = Builders.Filter.And( + Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"), + Builders.Filter.Eq(x => x.Metadata["private"], false), + Builders.Filter.Eq(x => x.Filename, $"{fileId}") + ); + + var (list, result) = Download(filter, _bucketName); + + if (!result.IsSuccess || list == null) + return (null, result); + + return (list.First(), result); + } + /// /// @@ -62,7 +77,30 @@ namespace DataProviders.Buckets { /// /// /// - public IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId) => DeleteOne(siteId, userId, fileId, _bucketName); + public (BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId) { + + var filter = Builders.Filter.And( + Builders.Filter.Eq(x => x.Metadata["siteId"], $"{siteId}"), + Builders.Filter.Eq(x => x.Metadata["userId"], $"{userId}"), + Builders.Filter.Eq(x => x.Filename, $"{fileId}") + ); + + var (list, result) = Download(filter, _bucketName); + + if (!result.IsSuccess || list == null) + return (null, result); + + return (list.First(), result); + } + + /// + /// + /// + /// + /// + /// + /// + public IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId) => DeleteOne(siteId, userId, fileId, _bucketName); /// /// diff --git a/webapi/DataProviders/Buckets/IBucketDataProvider.cs b/webapi/DataProviders/Buckets/ImageBucketDataProvider.cs similarity index 62% rename from webapi/DataProviders/Buckets/IBucketDataProvider.cs rename to webapi/DataProviders/Buckets/ImageBucketDataProvider.cs index a5e39ed..95b7a95 100644 --- a/webapi/DataProviders/Buckets/IBucketDataProvider.cs +++ b/webapi/DataProviders/Buckets/ImageBucketDataProvider.cs @@ -1,10 +1,17 @@ -using DomainResults.Common; +using Microsoft.Extensions.Logging; + +using DomainResults.Common; + +using MongoDB.Driver; + +using DataProviders.Abstractions; namespace DataProviders.Buckets { + /// /// /// - public interface IBucketDataProvider { + public interface IImageBucketDataProvider { /// /// @@ -24,6 +31,14 @@ namespace DataProviders.Buckets { /// (List?, IDomainResult) UploadMany(Guid siteId, Guid userId, List files); + /// + /// + /// + /// + /// + /// + (BucketFile?, IDomainResult) Download(Guid siteId, Guid fileId); + /// /// /// @@ -50,4 +65,20 @@ namespace DataProviders.Buckets { /// IDomainResult DeletMany(Guid siteId, Guid userId); } + + /// + /// + /// + public class ImageBucketDataProvider : SpecificBucketDataProviderBase, IImageBucketDataProvider { + + /// + /// + /// + /// + /// + public ImageBucketDataProvider( + ILogger logger, + IMongoClient client + ) : base(logger, client, "images") { } + } } diff --git a/webapi/DataProviders/Buckets/ImagesBucketDataProvider.cs b/webapi/DataProviders/Buckets/ImagesBucketDataProvider.cs deleted file mode 100644 index 3fd101f..0000000 --- a/webapi/DataProviders/Buckets/ImagesBucketDataProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Extensions.Logging; - -using DomainResults.Common; - -using MongoDB.Driver; - -using DataProviders.Abstractions; - -namespace DataProviders.Buckets { - - /// - /// - /// - public class ImagesBucketDataProvider : SpecificBucketDataProviderBase, IBucketDataProvider { - - /// - /// - /// - /// - /// - public ImagesBucketDataProvider( - ILogger logger, - IMongoClient client - ) : base(logger, client, "images") { } - } -} diff --git a/webapi/DataProviders/Collections/ContentDataProvider.cs b/webapi/DataProviders/Collections/ContentDataProvider.cs index c7dd3fd..7eaac6d 100644 --- a/webapi/DataProviders/Collections/ContentDataProvider.cs +++ b/webapi/DataProviders/Collections/ContentDataProvider.cs @@ -11,7 +11,7 @@ using Core.DomainObjects.Documents; namespace DataProviders.Collections { public interface IContentDataProvider { - (Content?, IDomainResult) Get(Guid siteId, string locale); + (List?, IDomainResult) Get(Guid siteId); } public class ContentDataProvider : CollectionDataProviderBase, IContentDataProvider { @@ -24,14 +24,6 @@ namespace DataProviders.Collections { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { } - public (Content?, IDomainResult) Get(Guid siteId, string locale) { - var (list, result) = GetWithPredicate(x => x.SiteId == siteId - && (x.Localization.Locale == null || x.Localization.Locale.ToLower() == locale.ToLower()), 0, 0, _collectionName); - - if (!result.IsSuccess || list == null) - return (null, result); - - return (list.First(), result); - } + public (List?, IDomainResult) Get(Guid siteId) => GetWithPredicate(x => x.SiteId == siteId, _collectionName); } } diff --git a/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs b/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs index 77deb48..b7e5a13 100644 --- a/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs +++ b/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs @@ -29,7 +29,7 @@ namespace DataProviders.Extensions #endregion #region Buckets - services.AddSingleton(); + services.AddSingleton(); #endregion } } diff --git a/webapi/Services/ImageProvider/Extensions/IImageProcessingContextExtensions.cs b/webapi/Services/ImageProvider/Extensions/IImageProcessingContextExtensions.cs new file mode 100644 index 0000000..ef15987 --- /dev/null +++ b/webapi/Services/ImageProvider/Extensions/IImageProcessingContextExtensions.cs @@ -0,0 +1,107 @@ +using System; +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Processing; + +namespace ImageProvider.Extensions { + internal static class IImageProcessingContextExtensions { + internal static IImageProcessingContext ApplyScalingWaterMark(this IImageProcessingContext processingContext, Font font, string text, Color color, float padding, bool wordwrap) { + if (wordwrap) { + return processingContext.ApplyScalingWaterMarkWordWrap(font, text, color, padding); + } + else { + return processingContext.ApplyScalingWaterMarkSimple(font, text, color, padding); + } + } + + internal static IImageProcessingContext ApplyScalingWaterMarkSimple(this IImageProcessingContext processingContext, + Font font, + string text, + Color color, + float padding) { + Size imgSize = processingContext.GetCurrentSize(); + + float targetWidth = imgSize.Width - (padding * 2); + float targetHeight = imgSize.Height - (padding * 2); + + // measure the text size + FontRectangle size = TextMeasurer.Measure(text, new RendererOptions(font)); + + //find out how much we need to scale the text to fill the space (up or down) + float scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height); + + //create a new font + Font scaledFont = new Font(font, scalingFactor * font.Size); + + var center = new PointF(imgSize.Width / 2, imgSize.Height / 2); + var textGraphicOptions = new TextGraphicsOptions() { + TextOptions = { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + } + }; + return processingContext.DrawText(textGraphicOptions, text, scaledFont, color, center); + } + + internal static IImageProcessingContext ApplyScalingWaterMarkWordWrap(this IImageProcessingContext processingContext, + Font font, + string text, + Color color, + float padding) { + Size imgSize = processingContext.GetCurrentSize(); + float targetWidth = imgSize.Width - (padding * 2); + float targetHeight = imgSize.Height - (padding * 2); + + float targetMinHeight = imgSize.Height - (padding * 3); // must be with in a margin width of the target height + + // now we are working i 2 dimensions at once and can't just scale because it will cause the text to + // reflow we need to just try multiple times + + var scaledFont = font; + FontRectangle s = new FontRectangle(0, 0, float.MaxValue, float.MaxValue); + + float scaleFactor = (scaledFont.Size / 2); // every time we change direction we half this size + int trapCount = (int)scaledFont.Size * 2; + if (trapCount < 10) { + trapCount = 10; + } + + bool isTooSmall = false; + + while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0) { + if (s.Height > targetHeight) { + if (isTooSmall) { + scaleFactor = scaleFactor / 2; + } + + scaledFont = new Font(scaledFont, scaledFont.Size - scaleFactor); + isTooSmall = false; + } + + if (s.Height < targetMinHeight) { + if (!isTooSmall) { + scaleFactor = scaleFactor / 2; + } + scaledFont = new Font(scaledFont, scaledFont.Size + scaleFactor); + isTooSmall = true; + } + trapCount--; + + s = TextMeasurer.Measure(text, new RendererOptions(scaledFont) { + WrappingWidth = targetWidth + }); + } + + var center = new PointF(padding, imgSize.Height / 2); + var textGraphicOptions = new TextGraphicsOptions() { + TextOptions = { + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Center, + WrapTextWidth = targetWidth + } + }; + return processingContext.DrawText(textGraphicOptions, text, scaledFont, color, center); + } + } +} diff --git a/webapi/Services/ImageProvider/Extensions/ServiceCollectionExtensions.cs b/webapi/Services/ImageProvider/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..f31c6b2 --- /dev/null +++ b/webapi/Services/ImageProvider/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; + +using SixLabors.Fonts; + +namespace ImageProvider.Extensions { + public static class ServiceCollectionExtensions { + public static void RegisterImageProvider(this IServiceCollection services) { + services.AddSingleton(x => { + var fontCollection = new FontCollection(); + + foreach (var font in Directory.EnumerateFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts"), "*.ttf", SearchOption.AllDirectories)) + fontCollection.Install(font); + + return fontCollection; + }); + + services.AddSingleton(); + } + } +} diff --git a/webapi/Services/ImageProvider/Fonts/FontStylesEnum.cs b/webapi/Services/ImageProvider/Fonts/FontStylesEnum.cs new file mode 100644 index 0000000..40eb5c9 --- /dev/null +++ b/webapi/Services/ImageProvider/Fonts/FontStylesEnum.cs @@ -0,0 +1,23 @@ +using Core.Abstractions; +using SixLabors.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageProvider.Fonts { + public class FontStylesEnum : Enumeration { + + public FontStyle FontStyle { get; private set; } + + public static FontStylesEnum Regular = new(0, "Regular", FontStyle.Regular); + public static FontStylesEnum Bold = new(0, "Bold", FontStyle.Bold); + public static FontStylesEnum Italic = new(0, "Italic", FontStyle.Italic); + public static FontStylesEnum BoldItalic = new(0, "BoldItalic", FontStyle.BoldItalic); + + private FontStylesEnum(int id, string displayName, FontStyle fontStyle) : base(id, displayName) { + FontStyle = fontStyle; + } + } +} diff --git a/webapi/Services/ImageProvider/Fonts/FontsEnum.cs b/webapi/Services/ImageProvider/Fonts/FontsEnum.cs new file mode 100644 index 0000000..0762006 --- /dev/null +++ b/webapi/Services/ImageProvider/Fonts/FontsEnum.cs @@ -0,0 +1,10 @@ +using Core.Abstractions; + +namespace ImageProvider.Fonts { + public class FontsEnum : Enumeration { + + public static FontsEnum Montserrat = new(0, "Montserrat"); + + private FontsEnum(int id, string displayName) : base(id, displayName) { } + } +} diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Black.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Black.ttf new file mode 100644 index 0000000..437b115 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Black.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BlackItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BlackItalic.ttf new file mode 100644 index 0000000..5234835 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BlackItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Bold.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Bold.ttf new file mode 100644 index 0000000..221819b Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Bold.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BoldItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BoldItalic.ttf new file mode 100644 index 0000000..9ae2bd2 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-BoldItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBold.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBold.ttf new file mode 100644 index 0000000..80ea806 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBold.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf new file mode 100644 index 0000000..6c961e1 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLight.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLight.ttf new file mode 100644 index 0000000..ca0bbb6 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLight.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLightItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLightItalic.ttf new file mode 100644 index 0000000..f3c1559 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ExtraLightItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Italic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Italic.ttf new file mode 100644 index 0000000..eb4232a Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Italic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Light.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Light.ttf new file mode 100644 index 0000000..990857d Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Light.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-LightItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-LightItalic.ttf new file mode 100644 index 0000000..2096040 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-LightItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Medium.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Medium.ttf new file mode 100644 index 0000000..6e079f6 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Medium.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-MediumItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-MediumItalic.ttf new file mode 100644 index 0000000..0dc3ac9 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-MediumItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Regular.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Regular.ttf new file mode 100644 index 0000000..8d443d5 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Regular.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBold.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBold.ttf new file mode 100644 index 0000000..f8a43f2 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBold.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBoldItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBoldItalic.ttf new file mode 100644 index 0000000..336c56e Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-SemiBoldItalic.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Thin.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Thin.ttf new file mode 100644 index 0000000..b985875 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-Thin.ttf differ diff --git a/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ThinItalic.ttf b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ThinItalic.ttf new file mode 100644 index 0000000..e488998 Binary files /dev/null and b/webapi/Services/ImageProvider/Fonts/Montserrat/Montserrat-ThinItalic.ttf differ diff --git a/webapi/Services/ImageProvider/ImageBuilder.cs b/webapi/Services/ImageProvider/ImageBuilder.cs new file mode 100644 index 0000000..c8927b2 --- /dev/null +++ b/webapi/Services/ImageProvider/ImageBuilder.cs @@ -0,0 +1,101 @@ +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Pbm; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Webp; +using SixLabors.ImageSharp.Processing; + +using ImageProvider.Extensions; + +namespace ImageProvider { + public class ImageBuilder : IDisposable { + + private Image _image; + + /// + /// + /// + /// + public ImageBuilder(byte[] bytes) { + _image = Image.Load(bytes); + } + + public void Load(byte[] bytes) { + _image = Image.Load(bytes); + } + + /// + /// + /// + /// for scaling water mark size is largely ignored. + /// + public void Watermark(Font font, string text) => + _image = _image.Clone(ctx => ctx.ApplyScalingWaterMark(font, text, Color.HotPink, 5, false)); + + /// + /// + /// + /// for scaling water mark size is largely ignored. + /// + public void WatermarkWordWrap(Font font, string longText) => + _image = _image.Clone(ctx => ctx.ApplyScalingWaterMark(font, longText, Color.HotPink, 5, true)); + + /// + /// + /// + /// + /// + public void Resize(int width, int height) => + _image.Mutate(img => img.Resize(width, height)); + + public void FitWidthResize(int width) { + _image.Mutate(x => x.Resize(new ResizeOptions { + Size = new Size(width, width), + Mode = ResizeMode.Max + })); + } + + public void FitHeightResize(int height) { + _image.Mutate(x => x.Resize(new ResizeOptions { + Size = new Size(height, height), + Mode = ResizeMode.Max + })); + } + + public void Crop(int cWidth, int cHeigth) => + Crop((_image.Width - cWidth) / 2, (_image.Height - cHeigth) / 2, cWidth, cHeigth); + + public void Crop(int x, int y, int cWidth, int cHeigth) => + _image.Mutate(img => img.Crop(new Rectangle(x, y, cWidth, cHeigth))); + + + + private byte[] Buid(IImageEncoder encoder) { + using var ms = new MemoryStream(); + _image.Save(ms, encoder); + + return ms.ToArray(); + } + + public byte[] ToGif() => Buid(new GifEncoder()); + + public byte[] ToJpeg() => Buid(new JpegEncoder()); + + public byte[] ToPbm() => Buid(new PbmEncoder()); + + public byte[] ToPng() => Buid(new PngEncoder()); + + public byte[] ToTga() => Buid(new TgaEncoder()); + + public byte[] ToTiff() => Buid(new TiffEncoder()); + + public byte[] ToWebp() => Buid(new WebpEncoder()); + + public void Dispose() => _image.Dispose(); + } +} \ No newline at end of file diff --git a/webapi/Services/ImageProvider/ImageProvider.cs b/webapi/Services/ImageProvider/ImageProvider.cs new file mode 100644 index 0000000..e6f87da --- /dev/null +++ b/webapi/Services/ImageProvider/ImageProvider.cs @@ -0,0 +1,69 @@ +using DomainResults.Common; +using ImageProvider.Fonts; +using Microsoft.Extensions.Logging; +using SixLabors.Fonts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageProvider { + + public interface IImageProvider { + (byte[]?, IDomainResult) Resize(byte[] bytes, int width, int height); + (byte[]?, IDomainResult) ResizeAndWatermark(byte[] bytes, int width, int height, FontsEnum fontName, FontStylesEnum fontStyle, string text); + } + + public class ImageProvider : IImageProvider { + + private readonly ILogger _logger; + private readonly IFontCollection _fontCollection; + + public ImageProvider( + ILogger logger, + IFontCollection fontCollection + ) { + _logger = logger; + _fontCollection = fontCollection; + } + + /// + /// + /// + /// + /// + /// + /// + public (byte[]?, IDomainResult) Resize(byte[] bytes, int width, int height) { + try { + using var imageBuilder = new ImageBuilder(bytes); + imageBuilder.Resize(width, height); + + return IDomainResult.Success(imageBuilder.ToJpeg()); + } + catch (Exception ex) { + _logger.LogError("Unhandled exception", ex); + return IDomainResult.Failed(); + } + } + + public (byte[]?, IDomainResult) ResizeAndWatermark(byte[] bytes, int width, int height, FontsEnum fontName, FontStylesEnum fontStyle, string text) { + try { + var font = _fontCollection.Families.Single(x => x.Name == fontName.Name) + .CreateFont(10, fontStyle.FontStyle); + + using var imageBuilder = new ImageBuilder(bytes); + imageBuilder.FitWidthResize(width); + imageBuilder.Crop(width, height); + // imageBuilder.Watermark(font, text); + + return IDomainResult.Success(imageBuilder.ToJpeg()); + } + catch (Exception ex) { + _logger.LogError("Unhandled exception", ex); + return IDomainResult.Failed(); + } + } + } +} diff --git a/webapi/Services/ImageProvider/ImageProvider.csproj b/webapi/Services/ImageProvider/ImageProvider.csproj new file mode 100644 index 0000000..0b5b0d5 --- /dev/null +++ b/webapi/Services/ImageProvider/ImageProvider.csproj @@ -0,0 +1,78 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/webapi/Services/ImageService/Class1.cs b/webapi/Services/ImageService/Class1.cs deleted file mode 100644 index 9aad34a..0000000 --- a/webapi/Services/ImageService/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ImageService { - public class Class1 { - - } -} \ No newline at end of file diff --git a/webapi/Services/ImageService/ImageService.csproj b/webapi/Services/ImageService/ImageService.csproj deleted file mode 100644 index 132c02c..0000000 --- a/webapi/Services/ImageService/ImageService.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net6.0 - enable - enable - - - diff --git a/webapi/WeatherForecast.sln b/webapi/WeatherForecast.sln index f733df7..f8ca220 100644 --- a/webapi/WeatherForecast.sln +++ b/webapi/WeatherForecast.sln @@ -27,7 +27,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensionsTests", "Tests\Ex EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageService", "Services\ImageService\ImageService.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProvider", "Services\ImageProvider\ImageProvider.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSecurityService", "Services\FileSecurityService\FileSecurityService.csproj", "{AD515653-9145-4894-9017-0ABA5A5892F4}" EndProject diff --git a/webapi/WeatherForecast/Controllers/ImageController.cs b/webapi/WeatherForecast/Controllers/ImageController.cs new file mode 100644 index 0000000..0920acf --- /dev/null +++ b/webapi/WeatherForecast/Controllers/ImageController.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +using WeatherForecast.Services; +using DomainResults.Mvc; + +namespace WeatherForecast.Controllers { + + /// + /// + /// + [AllowAnonymous] + [Route("api/[controller]")] + [ApiController] + public class ImageController : ControllerBase { + + private readonly IImageService _imageService; + + /// + /// + /// + /// + public ImageController( + IImageService imgeService + ) { + _imageService = imgeService; + } + + /// + /// + /// + /// + /// + /// + /// + /// + [HttpGet("{siteId}/{width}x{height}/{imageId}")] + public IActionResult Get([FromRoute] Guid siteId, [FromRoute] int width, [FromRoute] int height, [FromRoute] Guid imageId) { + + var (file, result) = _imageService.Get(siteId, width, height, imageId); + + if (!result.IsSuccess || file == null) + return result.ToActionResult(); + + var stream = new MemoryStream(file.Bytes); + return new FileStreamResult(stream, file.ContentType) { + FileDownloadName = file.Name + }; + } + + } +} diff --git a/webapi/WeatherForecast/Models/Requests/ShopItemRequestModel.cs b/webapi/WeatherForecast/Models/Requests/ShopItemRequestModel.cs index b098089..efac725 100644 --- a/webapi/WeatherForecast/Models/Requests/ShopItemRequestModel.cs +++ b/webapi/WeatherForecast/Models/Requests/ShopItemRequestModel.cs @@ -49,11 +49,10 @@ namespace WeatherForecast.Models.Requests { return new ShopItem() { L10n = L10n.Select(x => x.ToDomainObject()).ToList(), - // Images + MediaAttachments = MediaAttachments?.Select(x => x.ToDomainObject()).ToList(), // Author Created = DateTime.UtcNow, Tags = Tags, - Categories = Categories, FamilyFriendly = FamilyFriendly, BrandName = BrandName, diff --git a/webapi/WeatherForecast/Services/BlogItemService.cs b/webapi/WeatherForecast/Services/BlogItemService.cs index f1f62ab..ed4f743 100644 --- a/webapi/WeatherForecast/Services/BlogItemService.cs +++ b/webapi/WeatherForecast/Services/BlogItemService.cs @@ -87,12 +87,12 @@ namespace WeatherForecast.Services { /// /// /// - /// + /// /// /// - public (Guid?, IDomainResult) Post(Guid siteId, BlogItemRequestModel requestModel) { + public (Guid?, IDomainResult) Post(Guid siteId, BlogItemRequestModel requestData) { try { - var item = requestModel.ToDomainObject(); + var item = requestData.ToDomainObject(); item.SiteId = siteId; var (_, getResult) = _blogCatalogDataProvider.GetBySlugs(item.SiteId, item.L10n.Select(x => x.Slug).ToList()); @@ -102,7 +102,7 @@ namespace WeatherForecast.Services { // TODO: should be recovered from users by jwt item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid(); - var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, item.Categories); + var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, requestData.Categories); if (!addCategoriesResult.IsSuccess || categories == null) return (null, addCategoriesResult); @@ -194,7 +194,7 @@ namespace WeatherForecast.Services { newItem.Created = item.Created; newItem.Author = item.Author; - var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, item.Categories); + var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, requestData.Categories); if (!addCategoriesResult.IsSuccess || categories == null) return (null, addCategoriesResult); diff --git a/webapi/WeatherForecast/Services/ContentService.cs b/webapi/WeatherForecast/Services/ContentService.cs index fcdcaa4..b138718 100644 --- a/webapi/WeatherForecast/Services/ContentService.cs +++ b/webapi/WeatherForecast/Services/ContentService.cs @@ -49,12 +49,11 @@ namespace WeatherForecast.Services { /// public (ContentResponseModel?, IDomainResult) GetContent(Guid siteId, string locale) { try { - var (content, result) = _contentDataProvider.Get(siteId, locale); - + var (content, result) = _contentDataProvider.Get(siteId); if (!result.IsSuccess || content == null) return (null, result); - return IDomainResult.Success(new ContentResponseModel(content)); + return IDomainResult.Success(new ContentResponseModel(content.Single(x => x.Localization.Locale == locale))); } catch (Exception ex) { _logger.LogError(ex, "Unhandled exception"); diff --git a/webapi/WeatherForecast/Services/FileService.cs b/webapi/WeatherForecast/Services/FileService.cs index 1b73d29..8e4da78 100644 --- a/webapi/WeatherForecast/Services/FileService.cs +++ b/webapi/WeatherForecast/Services/FileService.cs @@ -44,7 +44,7 @@ namespace WeatherForecast.Services { private readonly ILogger _logger; private readonly IFilesService _filesService; - private readonly IBucketDataProvider _imageBucketDataProvider; + private readonly IImageBucketDataProvider _imageBucketDataProvider; /// /// @@ -55,7 +55,7 @@ namespace WeatherForecast.Services { public FileService( ILogger logger, IFilesService filesService, - IBucketDataProvider imageBucketDataProvider + IImageBucketDataProvider imageBucketDataProvider ) { _logger = logger; _filesService = filesService; diff --git a/webapi/WeatherForecast/Services/FilesService.cs b/webapi/WeatherForecast/Services/FilesService.cs index 8b97056..e3cb55b 100644 --- a/webapi/WeatherForecast/Services/FilesService.cs +++ b/webapi/WeatherForecast/Services/FilesService.cs @@ -35,7 +35,7 @@ namespace WeatherForecast.Services { private readonly ILogger _logger; private readonly IFileSecurityService _fileSecurityService; - private readonly IBucketDataProvider _imageBucketDataProvider; + private readonly IImageBucketDataProvider _imageBucketDataProvider; /// /// @@ -45,7 +45,7 @@ namespace WeatherForecast.Services { public FilesService( ILogger logger, IFileSecurityService fileSecurityService, - IBucketDataProvider imageBucketDataProvider + IImageBucketDataProvider imageBucketDataProvider ) { _logger = logger; _fileSecurityService = fileSecurityService; diff --git a/webapi/WeatherForecast/Services/ImageService.cs b/webapi/WeatherForecast/Services/ImageService.cs new file mode 100644 index 0000000..b331401 --- /dev/null +++ b/webapi/WeatherForecast/Services/ImageService.cs @@ -0,0 +1,88 @@ + +using DataProviders; +using DataProviders.Buckets; +using DataProviders.Collections; +using DomainResults.Common; +using ImageProvider; +using ImageProvider.Fonts; + +namespace WeatherForecast.Services { + + /// + /// + /// + public interface IImageService { + /// + /// + /// + /// + /// + /// + /// + /// + (BucketFile?, IDomainResult) Get(Guid siteId, int width, int height, Guid imageId); + } + + /// + /// + /// + public class ImageService : IImageService { + + private readonly ILogger _logger; + private readonly IImageBucketDataProvider _imageBucketDataProvider; + private readonly IImageProvider _imageProvider; + private readonly IContentDataProvider _contentDataProvider; + + /// + /// + /// + /// + /// + /// + public ImageService( + ILogger logger, + IImageBucketDataProvider imageBucketDataProvider, + IImageProvider imageProvider, + IContentDataProvider contentDataProvider + + ) { + _logger = logger; + _imageBucketDataProvider = imageBucketDataProvider; + _imageProvider = imageProvider; + _contentDataProvider = contentDataProvider; + } + + /// + /// + /// + /// + /// + /// + /// + /// + public (BucketFile?, IDomainResult) Get(Guid siteId, int width, int height, Guid imageId) { + try { + var (file, downloadResult) = _imageBucketDataProvider.Download(siteId, imageId); + if (!downloadResult.IsSuccess || file == null) + return IDomainResult.Failed (); + + var (content, getContentResult) = _contentDataProvider.Get(siteId); + if (!getContentResult.IsSuccess || content == null) + return IDomainResult.Failed(); + + var (image, transformResult) = _imageProvider.ResizeAndWatermark(file.Bytes, width, height, FontsEnum.Montserrat, FontStylesEnum.Regular, content.First().SiteName); + if (!transformResult.IsSuccess || image == null) + return IDomainResult.Failed(); + + return IDomainResult.Success(new BucketFile(file.Name, image, "image/jpeg")); + } + catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); + return IDomainResult.Failed (ex.Message); + } + + } + + + } +} diff --git a/webapi/WeatherForecast/Services/ShopItemService.cs b/webapi/WeatherForecast/Services/ShopItemService.cs index f208080..2fe03a0 100644 --- a/webapi/WeatherForecast/Services/ShopItemService.cs +++ b/webapi/WeatherForecast/Services/ShopItemService.cs @@ -89,11 +89,11 @@ namespace WeatherForecast.Services { /// /// /// - /// + /// /// - public (Guid?, IDomainResult) Post(Guid siteId, string sku, ShopItemRequestModel requestModel) { + public (Guid?, IDomainResult) Post(Guid siteId, string sku, ShopItemRequestModel requestData) { try { - var item = requestModel.ToDomainObject(); + var item = requestData.ToDomainObject(); item.SiteId = siteId; item.Sku = sku; @@ -105,7 +105,7 @@ namespace WeatherForecast.Services { // TODO: should be recovered from users by jwt item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid(); - var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, item.Categories); + var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, requestData.Categories); if (!addCategoriesResult.IsSuccess || categories == null) return (null, addCategoriesResult); @@ -197,7 +197,7 @@ namespace WeatherForecast.Services { newItem.Created = item.Created; newItem.Author = item.Author; - var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, item.Categories); + var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(siteId, requestData.Categories); if (!addCategoriesResult.IsSuccess || categories == null) return (null, addCategoriesResult); diff --git a/webapi/WeatherForecast/Startup.cs b/webapi/WeatherForecast/Startup.cs index fd41914..c2d8c57 100644 --- a/webapi/WeatherForecast/Startup.cs +++ b/webapi/WeatherForecast/Startup.cs @@ -7,6 +7,7 @@ using WeatherForecast.Services; using DataProviders.Extensions; using System.Text.Json.Serialization; using FileSecurityService.Extensions; +using ImageProvider.Extensions; namespace WeatherForecast { @@ -83,9 +84,11 @@ namespace WeatherForecast { services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.RegisterDataproviders(appSettings); services.RegisterFileSecurityService(); + services.RegisterImageProvider(); #region Swagger services.ConfigureSwaggerGen(options => { diff --git a/webapi/WeatherForecast/WeatherForecast.csproj b/webapi/WeatherForecast/WeatherForecast.csproj index 21c30cf..d424e55 100644 --- a/webapi/WeatherForecast/WeatherForecast.csproj +++ b/webapi/WeatherForecast/WeatherForecast.csproj @@ -29,6 +29,7 @@ +