diff --git a/src/Client/Client.cs b/src/Client/Client.cs index 66ab162..ec0ea18 100644 --- a/src/Client/Client.cs +++ b/src/Client/Client.cs @@ -36,7 +36,7 @@ public class Client public async Task SearchdomainListAsync() { - return await GetUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "List", apiKey, [])); + return await GetUrlAndProcessJson(GetUrl($"{baseUri}", "Searchdomains", apiKey, [])); } public async Task SearchdomainDeleteAsync() @@ -46,7 +46,7 @@ public class Client public async Task SearchdomainDeleteAsync(string searchdomain) { - return await GetUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "Delete", apiKey, new Dictionary() + return await DeleteUrlAndProcessJson(GetUrl($"{baseUri}", "Searchdomain", apiKey, new Dictionary() { {"searchdomain", searchdomain} })); @@ -57,12 +57,12 @@ public class Client return await SearchdomainCreateAsync(searchdomain); } - public async Task SearchdomainCreateAsync(string searchdomain) + public async Task SearchdomainCreateAsync(string searchdomain, SearchdomainSettings searchdomainSettings = new()) { - return await GetUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "Create", apiKey, new Dictionary() + return await PostUrlAndProcessJson(GetUrl($"{baseUri}", "Searchdomain", apiKey, new Dictionary() { {"searchdomain", searchdomain} - })); + }), new StringContent(JsonSerializer.Serialize(searchdomainSettings), Encoding.UTF8, "application/json")); } public async Task SearchdomainUpdateAsync(string newName, string settings = "{}") @@ -72,14 +72,18 @@ public class Client return updateResults; } + public async Task SearchdomainUpdateAsync(string searchdomain, string newName, SearchdomainSettings settings = new()) + { + return await SearchdomainUpdateAsync(searchdomain, newName, JsonSerializer.Serialize(settings)); + } + public async Task SearchdomainUpdateAsync(string searchdomain, string newName, string settings = "{}") { - return await GetUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "Update", apiKey, new Dictionary() + return await PutUrlAndProcessJson(GetUrl($"{baseUri}", "Searchdomain", apiKey, new Dictionary() { {"searchdomain", searchdomain}, - {"newName", newName}, - {"settings", settings} - })); + {"newName", newName} + }), new StringContent(settings, Encoding.UTF8, "application/json")); } public async Task EntityQueryAsync(string query) @@ -89,11 +93,11 @@ public class Client public async Task EntityQueryAsync(string searchdomain, string query) { - return await GetUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "Query", apiKey, new Dictionary() + return await PostUrlAndProcessJson(GetUrl($"{baseUri}/Searchdomain", "Query", apiKey, new Dictionary() { {"searchdomain", searchdomain}, {"query", query} - })); + }), null); } public async Task EntityIndexAsync(List jsonEntity) @@ -104,7 +108,7 @@ public class Client public async Task EntityIndexAsync(string jsonEntity) { var content = new StringContent(jsonEntity, Encoding.UTF8, "application/json"); - return await PostUrlAndProcessJson(GetUrl($"{baseUri}/Entity", "Index", apiKey, []), content);//new FormUrlEncodedContent(values)); + return await PutUrlAndProcessJson(GetUrl($"{baseUri}", "Entity", apiKey, []), content); } public async Task EntityListAsync(bool returnEmbeddings = false) @@ -114,7 +118,7 @@ public class Client public async Task EntityListAsync(string searchdomain, bool returnEmbeddings = false) { - var url = $"{baseUri}/Entity/List?apiKey={HttpUtility.UrlEncode(apiKey)}&searchdomain={HttpUtility.UrlEncode(searchdomain)}&returnEmbeddings={HttpUtility.UrlEncode(returnEmbeddings.ToString())}"; + var url = $"{baseUri}/Entities?apiKey={HttpUtility.UrlEncode(apiKey)}&searchdomain={HttpUtility.UrlEncode(searchdomain)}&returnEmbeddings={HttpUtility.UrlEncode(returnEmbeddings.ToString())}"; return await GetUrlAndProcessJson(url); } @@ -125,8 +129,8 @@ public class Client public async Task EntityDeleteAsync(string searchdomain, string entityName) { - var url = $"{baseUri}/Entity/Delete?apiKey={HttpUtility.UrlEncode(apiKey)}&searchdomain={HttpUtility.UrlEncode(searchdomain)}&entity={HttpUtility.UrlEncode(entityName)}"; - return await GetUrlAndProcessJson(url); + var url = $"{baseUri}/Entity?apiKey={HttpUtility.UrlEncode(apiKey)}&searchdomain={HttpUtility.UrlEncode(searchdomain)}&entity={HttpUtility.UrlEncode(entityName)}"; + return await DeleteUrlAndProcessJson(url); } private static async Task GetUrlAndProcessJson(string url) @@ -138,7 +142,8 @@ public class Client ?? throw new Exception($"Failed to deserialize JSON to type {typeof(T).Name}"); return result; } - private static async Task PostUrlAndProcessJson(string url, HttpContent content) + + private static async Task PostUrlAndProcessJson(string url, HttpContent? content) { using var client = new HttpClient(); var response = await client.PostAsync(url, content); @@ -148,6 +153,26 @@ public class Client return result; } + private static async Task PutUrlAndProcessJson(string url, HttpContent content) + { + using var client = new HttpClient(); + var response = await client.PutAsync(url, content); + string responseContent = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize(responseContent) + ?? throw new Exception($"Failed to deserialize JSON to type {typeof(T).Name}"); + return result; + } + + private static async Task DeleteUrlAndProcessJson(string url) + { + using var client = new HttpClient(); + var response = await client.DeleteAsync(url); + string responseContent = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize(responseContent) + ?? throw new Exception($"Failed to deserialize JSON to type {typeof(T).Name}"); + return result; + } + public static string GetUrl(string baseUri, string endpoint, string apiKey, Dictionary parameters) { var uriBuilder = new UriBuilder($"{baseUri}/{endpoint}"); diff --git a/src/Server/Controllers/EntityController.cs b/src/Server/Controllers/EntityController.cs index 0281c96..0637f08 100644 --- a/src/Server/Controllers/EntityController.cs +++ b/src/Server/Controllers/EntityController.cs @@ -24,7 +24,7 @@ public class EntityController : ControllerBase _databaseHelper = databaseHelper; } - [HttpPost("Index")] + [HttpPut] public ActionResult Index([FromBody] List? jsonEntities) { try @@ -62,7 +62,7 @@ public class EntityController : ControllerBase } - [HttpGet("List")] + [HttpGet("/Entities")] public ActionResult List(string searchdomain, bool returnModels = false, bool returnEmbeddings = false) { if (returnEmbeddings && !returnModels) @@ -109,7 +109,7 @@ public class EntityController : ControllerBase return Ok(entityListResults); } - [HttpGet("Delete")] + [HttpDelete] public ActionResult Delete(string searchdomain, string entityName) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); diff --git a/src/Server/Controllers/SearchdomainController.cs b/src/Server/Controllers/SearchdomainController.cs index 66d9aef..a300450 100644 --- a/src/Server/Controllers/SearchdomainController.cs +++ b/src/Server/Controllers/SearchdomainController.cs @@ -23,7 +23,7 @@ public class SearchdomainController : ControllerBase _domainManager = domainManager; } - [HttpGet("List")] + [HttpGet("/Searchdomains")] public ActionResult List() { List results; @@ -40,8 +40,8 @@ public class SearchdomainController : ControllerBase return Ok(searchdomainListResults); } - [HttpGet("Create")] - public ActionResult Create(string searchdomain, string settings = "{}") + [HttpPost] + public ActionResult Create(string searchdomain, [FromBody]SearchdomainSettings settings = new()) { try { @@ -54,7 +54,7 @@ public class SearchdomainController : ControllerBase } } - [HttpGet("Delete")] + [HttpDelete] public ActionResult Delete(string searchdomain) { bool success; @@ -84,22 +84,33 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainDeleteResults(){Success = success, DeletedEntities = deletedEntries, Message = message}); } - [HttpGet("Update")] - public ActionResult Update(string searchdomain, string newName, string settings = "{}") + [HttpPut] + public ActionResult Update(string searchdomain, string newName, [FromBody]string? settings = "{}") { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message}); - Dictionary parameters = new() + if (settings is null) { - {"name", newName}, - {"settings", settings}, - {"id", searchdomain_.id} - }; - searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name, settings = @settings WHERE id = @id", parameters); + Dictionary parameters = new() + { + {"name", newName}, + {"id", searchdomain_.id} + }; + searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name WHERE id = @id", parameters); + } else + { + Dictionary parameters = new() + { + {"name", newName}, + {"settings", settings}, + {"id", searchdomain_.id} + }; + searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name, settings = @settings WHERE id = @id", parameters); + } return Ok(new SearchdomainUpdateResults(){Success = true}); } - [HttpGet("Query")] + [HttpPost("Query")] public ActionResult Query(string searchdomain, string query, int? topN, bool returnAttributes = false) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); @@ -114,7 +125,7 @@ public class SearchdomainController : ControllerBase return Ok(new EntityQueryResults(){Results = queryResults, Success = true }); } - [HttpPost("UpdateSettings")] + [HttpPut("Settings")] public ActionResult UpdateSettings(string searchdomain, [FromBody] SearchdomainSettings request) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); @@ -129,8 +140,8 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainUpdateResults(){Success = true}); } - [HttpGet("GetSearches")] - public ActionResult GetSearches(string searchdomain) + [HttpGet("Queries")] + public ActionResult GetQueries(string searchdomain) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message}); @@ -139,8 +150,8 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainSearchesResults() { Searches = searchCache, Success = true }); } - [HttpDelete("Searches")] - public ActionResult DeleteSearch(string searchdomain, string query) + [HttpDelete("Query")] + public ActionResult DeleteQuery(string searchdomain, string query) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message}); @@ -154,8 +165,8 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainDeleteSearchResult() {Success = false, Message = "Query not found in search cache"}); } - [HttpPatch("Searches")] - public ActionResult UpdateSearch(string searchdomain, string query, [FromBody]List results) + [HttpPatch("Query")] + public ActionResult UpdateQuery(string searchdomain, string query, [FromBody]List results) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message}); @@ -171,7 +182,7 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainUpdateSearchResult() {Success = false, Message = "Query not found in search cache"}); } - [HttpGet("GetSettings")] + [HttpGet("Settings")] public ActionResult GetSettings(string searchdomain) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); @@ -180,7 +191,7 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainSettingsResults() { Settings = settings, Success = true }); } - [HttpGet("GetSearchCacheSize")] + [HttpGet("SearchCache/Size")] public ActionResult GetSearchCacheSize(string searchdomain) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); @@ -196,7 +207,7 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainSearchCacheSizeResults() { SearchCacheSizeBytes = sizeInBytes, Success = true }); } - [HttpGet("ClearSearchCache")] + [HttpPost("SearchCache/Clear")] public ActionResult InvalidateSearchCache(string searchdomain) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); @@ -205,7 +216,7 @@ public class SearchdomainController : ControllerBase return Ok(new SearchdomainInvalidateCacheResults(){Success = true}); } - [HttpGet("GetDatabaseSize")] + [HttpGet("Database/Size")] public ActionResult GetDatabaseSize(string searchdomain) { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); diff --git a/src/Server/Controllers/ServerController.cs b/src/Server/Controllers/ServerController.cs index ca4d9b8..238a3c6 100644 --- a/src/Server/Controllers/ServerController.cs +++ b/src/Server/Controllers/ServerController.cs @@ -22,7 +22,7 @@ public class ServerController : ControllerBase _aIProvider = aIProvider; } - [HttpGet("GetModels")] + [HttpGet("Models")] public ActionResult GetModels() { try diff --git a/src/Server/SearchdomainManager.cs b/src/Server/SearchdomainManager.cs index 81d1edb..8a00b4c 100644 --- a/src/Server/SearchdomainManager.cs +++ b/src/Server/SearchdomainManager.cs @@ -4,6 +4,8 @@ using Server.Migrations; using Server.Helper; using Server.Exceptions; using AdaptiveExpressions; +using Shared.Models; +using System.Text.Json; namespace Server; @@ -87,6 +89,10 @@ public class SearchdomainManager } } + public int CreateSearchdomain(string searchdomain, SearchdomainSettings settings) + { + return CreateSearchdomain(searchdomain, JsonSerializer.Serialize(settings)); + } public int CreateSearchdomain(string searchdomain, string settings = "{}") { if (searchdomains.TryGetValue(searchdomain, out Searchdomain? value)) diff --git a/src/Server/Views/Home/Index.cshtml b/src/Server/Views/Home/Index.cshtml index b167e0b..e2b5f2e 100644 --- a/src/Server/Views/Home/Index.cshtml +++ b/src/Server/Views/Home/Index.cshtml @@ -745,8 +745,8 @@ "datapoints": datapoints }]; showToast("@T["Creating entity"]", "primary"); - fetch(`/Entity/Index`, { - method: 'POST', + fetch(`/Entity`, { + method: 'PUT', headers: { 'Content-Type': 'application/json' }, @@ -778,8 +778,12 @@ const cacheReconciliation = document.getElementById('createSearchdomainWithCacheReconciliation').checked; const settings = { CacheReconciliation: cacheReconciliation }; // Implement create logic here - fetch(`/Searchdomain/Create?searchdomain=${encodeURIComponent(name)}&settings=${JSON.stringify(settings)}`, { - method: 'GET' + fetch(`/Searchdomain?searchdomain=${encodeURIComponent(name)}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(settings) }).then(response => { if (response.ok) { showToast("@T["Searchdomain was created successfully"]", "success"); @@ -800,8 +804,8 @@ .getElementById('cacheClear') .addEventListener('click', () => { const domainKey = getSelectedDomainKey(); - fetch(`/Searchdomain/ClearSearchCache?searchdomain=${encodeURIComponent(domains[domainKey])}`, { - method: 'GET' + fetch(`/Searchdomain/SearchCache/Clear?searchdomain=${encodeURIComponent(domains[domainKey])}`, { + method: 'POST' }).then(response => { if (response.ok) { showToast("@T["Searchdomain cache was cleared successfully"]", "success"); @@ -823,8 +827,8 @@ .addEventListener('click', () => { const domainKey = getSelectedDomainKey(); const entityName = document.getElementById('EntityConfirmDelete').getAttribute('data-name'); - fetch(`/Entity/Delete?searchdomain=${encodeURIComponent(domains[domainKey])}&entityName=${entityName}`, { - method: 'GET' + fetch(`/Entity?searchdomain=${encodeURIComponent(domains[domainKey])}&entityName=${entityName}`, { + method: 'DELETE' }).then(async response => { let result = await response.json(); if (response.ok && result.Success) { @@ -870,8 +874,8 @@ "datapoints": datapoints }]; showToast("@T["Updating entity"]", "primary"); - fetch(`/Entity/Index`, { - method: 'POST', + fetch(`/Entity`, { + method: 'PUT', headers: { 'Content-Type': 'application/json' }, @@ -897,7 +901,7 @@ .addEventListener('click', () => { let searchdomain = domains[getSelectedDomainKey()]; let query = document.getElementById('deleteQueryConfirmationModalName').textContent; - fetch(`/Searchdomain/Searches?searchdomain=${searchdomain}&query=${query}`, { + fetch(`/Searchdomain/Query?searchdomain=${searchdomain}&query=${query}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' @@ -924,7 +928,7 @@ let query = document.getElementById('queryUpdateQueryName').textContent; let data = getQueryUpdateTableData(); console.log() - fetch(`/Searchdomain/Searches?searchdomain=${searchdomain}&query=${query}`, { + fetch(`/Searchdomain/Query?searchdomain=${searchdomain}&query=${query}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' @@ -949,8 +953,8 @@ function deleteSearchdomain(domainKey) { // Implement delete logic here - fetch(`/Searchdomain/Delete?searchdomain=${encodeURI(domains[domainKey])}`, { - method: 'GET' + fetch(`/Searchdomain?searchdomain=${encodeURI(domains[domainKey])}`, { + method: 'DELETE' }).then(async response => { var result = await response.json();; if (response.ok && result.Success === true) { @@ -971,8 +975,8 @@ function renameSearchdomain(domainKey, newName) { // Implement rename logic here - fetch(`/Searchdomain/Update?searchdomain=${encodeURI(domains[domainKey])}&newName=${newName}`, { - method: 'GET' + fetch(`/Searchdomain?searchdomain=${encodeURI(domains[domainKey])}&newName=${newName}`, { + method: 'PUT' }).then(async response => { var result = await response.json(); if (response.ok && result.Success === true) { @@ -996,8 +1000,8 @@ function updateSearchdomainConfig(domainKey, newSettings) { // Implement update logic here - fetch(`/Searchdomain/UpdateSettings?searchdomain=${encodeURIComponent(domains[domainKey])}`, { - method: 'POST', + fetch(`/Searchdomain/Settings?searchdomain=${encodeURIComponent(domains[domainKey])}`, { + method: 'PUT', headers: { 'Content-Type': 'application/json' }, @@ -1022,17 +1026,17 @@ } function getSearchdomainConfig(domainKey) { - return fetch(`/Searchdomain/GetSettings?searchdomain=${encodeURIComponent(domains[domainKey])}`) + return fetch(`/Searchdomain/Settings?searchdomain=${encodeURIComponent(domains[domainKey])}`) .then(r => r.json()); } function getSearchdomainCacheUtilization(domainKey) { - return fetch(`/Searchdomain/GetSearchCacheSize?searchdomain=${encodeURIComponent(domains[domainKey])}`) + return fetch(`/Searchdomain/SearchCache/Size?searchdomain=${encodeURIComponent(domains[domainKey])}`) .then(r => r.json()); } function getSearchdomainDatabaseUtilization(domainKey) { - return fetch(`/Searchdomain/GetDatabaseSize?searchdomain=${encodeURIComponent(domains[domainKey])}`) + return fetch(`/Searchdomain/Database/Size?searchdomain=${encodeURIComponent(domains[domainKey])}`) .then(r => r.json()); } @@ -1054,7 +1058,7 @@ let databaseUtilizationPromise = getSearchdomainDatabaseUtilization(getSelectedDomainKey()); /* ---------- ENTITIES ---------- */ - let entitiesUrl = `/Entity/List?searchdomain=${encodeURIComponent(domainName)}&returnEmbeddings=false&returnModels=true`; + let entitiesUrl = `/Entities?searchdomain=${encodeURIComponent(domainName)}&returnEmbeddings=false&returnModels=true`; let entitiesCard = document.querySelector("#entitiesTable").parentElement; clearEntitiesTable(); showThrobber(entitiesCard); @@ -1073,7 +1077,7 @@ }); /* ---------- QUERIES ---------- */ - let queriesUrl = `/Searchdomain/GetSearches?searchdomain=${encodeURIComponent(domainName)}`; + let queriesUrl = `/Searchdomain/Queries?searchdomain=${encodeURIComponent(domainName)}`; let queriesCard = document.querySelector("#queriesTable").parentElement; clearQueriesTable(); showThrobber(queriesCard);