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 @@
+