Skip to content

Commit b3bc703

Browse files
Implement item tag backend
1 parent 03dc3f5 commit b3bc703

File tree

6 files changed

+335
-4
lines changed

6 files changed

+335
-4
lines changed

src/Certify.Models/Hub/ItemTag.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
/// </summary>
66
public class ItemTag : ConfigurationStoreItem
77
{
8-
public ItemTag(string itemId, string itemType, string tag, string? value)
8+
public ItemTag(string taggedItemId, string taggedItemType, string tag, string? value)
99
{
10-
TaggedItemId = itemId;
11-
TaggedItemType = itemType;
10+
TaggedItemId = taggedItemId;
11+
TaggedItemType = taggedItemType;
1212
Tag = tag;
1313
Value = value;
1414
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Certify.Management;
2+
using Certify.Models.Hub;
3+
using Microsoft.AspNetCore.Mvc;
4+
5+
namespace Certify.Service.Controllers
6+
{
7+
[ApiController]
8+
[Route("api/tags")]
9+
public class TagController : ControllerBase
10+
{
11+
private ICertifyManager _certifyManager;
12+
13+
public TagController(ICertifyManager certifyManager)
14+
{
15+
_certifyManager = certifyManager;
16+
}
17+
18+
[HttpPost, Route("add")]
19+
public async Task<Models.Config.ActionResult> AddTag([FromBody] ItemTag tag)
20+
{
21+
return await _certifyManager.AddHubItemTags([tag]);
22+
}
23+
24+
[HttpPost, Route("update")]
25+
public async Task<Models.Config.ActionResult> UpdateTag([FromBody] ItemTag tag)
26+
{
27+
throw new NotImplementedException("UpdateTag is not implemented yet. Use AddTag instead to create or update tags.");
28+
}
29+
30+
[HttpDelete, Route("delete/{id}")]
31+
public async Task<Models.Config.ActionResult> DeleteTag(string id)
32+
{
33+
return await _certifyManager.RemoveHubItemTags([id]);
34+
}
35+
36+
[HttpGet, Route("list")]
37+
public async Task<ICollection<ItemTag>> GetTags()
38+
{
39+
return await _certifyManager.GetAllHubItemTags();
40+
}
41+
}
42+
}

src/Certify.Server/Certify.Server.Hub.Api.Client/Certify.Server.Hub.Api.Client.cs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4157,6 +4157,178 @@ public virtual async System.Threading.Tasks.Task<ActionResult> RemoveHubManagedI
41574157
}
41584158
}
41594159

4160+
/// <summary>
4161+
/// Get hub item tags [Generated]
4162+
/// </summary>
4163+
/// <returns>OK</returns>
4164+
/// <exception cref="ApiException">A server side error occurred.</exception>
4165+
public virtual System.Threading.Tasks.Task<System.Collections.Generic.ICollection<ItemTag>> GetHubItemTagsAsync()
4166+
{
4167+
return GetHubItemTagsAsync(System.Threading.CancellationToken.None);
4168+
}
4169+
4170+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
4171+
/// <summary>
4172+
/// Get hub item tags [Generated]
4173+
/// </summary>
4174+
/// <returns>OK</returns>
4175+
/// <exception cref="ApiException">A server side error occurred.</exception>
4176+
public virtual async System.Threading.Tasks.Task<System.Collections.Generic.ICollection<ItemTag>> GetHubItemTagsAsync(System.Threading.CancellationToken cancellationToken)
4177+
{
4178+
var client_ = _httpClient;
4179+
var disposeClient_ = false;
4180+
try
4181+
{
4182+
using (var request_ = new System.Net.Http.HttpRequestMessage())
4183+
{
4184+
request_.Method = new System.Net.Http.HttpMethod("GET");
4185+
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
4186+
4187+
var urlBuilder_ = new System.Text.StringBuilder();
4188+
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
4189+
// Operation Path: "internal/v1/hub/tags/list"
4190+
urlBuilder_.Append("internal/v1/hub/tags/list");
4191+
4192+
PrepareRequest(client_, request_, urlBuilder_);
4193+
4194+
var url_ = urlBuilder_.ToString();
4195+
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
4196+
4197+
PrepareRequest(client_, request_, url_);
4198+
4199+
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
4200+
var disposeResponse_ = true;
4201+
try
4202+
{
4203+
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
4204+
foreach (var item_ in response_.Headers)
4205+
headers_[item_.Key] = item_.Value;
4206+
if (response_.Content != null && response_.Content.Headers != null)
4207+
{
4208+
foreach (var item_ in response_.Content.Headers)
4209+
headers_[item_.Key] = item_.Value;
4210+
}
4211+
4212+
ProcessResponse(client_, response_);
4213+
4214+
var status_ = (int)response_.StatusCode;
4215+
if (status_ == 200)
4216+
{
4217+
var objectResponse_ = await ReadObjectResponseAsync<System.Collections.Generic.ICollection<ItemTag>>(response_, headers_, cancellationToken).ConfigureAwait(false);
4218+
if (objectResponse_.Object == null)
4219+
{
4220+
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
4221+
}
4222+
return objectResponse_.Object;
4223+
}
4224+
else
4225+
{
4226+
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
4227+
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
4228+
}
4229+
}
4230+
finally
4231+
{
4232+
if (disposeResponse_)
4233+
response_.Dispose();
4234+
}
4235+
}
4236+
}
4237+
finally
4238+
{
4239+
if (disposeClient_)
4240+
client_.Dispose();
4241+
}
4242+
}
4243+
4244+
/// <summary>
4245+
/// Add hub item tag [Generated]
4246+
/// </summary>
4247+
/// <returns>OK</returns>
4248+
/// <exception cref="ApiException">A server side error occurred.</exception>
4249+
public virtual System.Threading.Tasks.Task<ActionResult> AddHubItemTagAsync(ItemTag body)
4250+
{
4251+
return AddHubItemTagAsync(body, System.Threading.CancellationToken.None);
4252+
}
4253+
4254+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
4255+
/// <summary>
4256+
/// Add hub item tag [Generated]
4257+
/// </summary>
4258+
/// <returns>OK</returns>
4259+
/// <exception cref="ApiException">A server side error occurred.</exception>
4260+
public virtual async System.Threading.Tasks.Task<ActionResult> AddHubItemTagAsync(ItemTag body, System.Threading.CancellationToken cancellationToken)
4261+
{
4262+
var client_ = _httpClient;
4263+
var disposeClient_ = false;
4264+
try
4265+
{
4266+
using (var request_ = new System.Net.Http.HttpRequestMessage())
4267+
{
4268+
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings);
4269+
var content_ = new System.Net.Http.StringContent(json_);
4270+
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
4271+
request_.Content = content_;
4272+
request_.Method = new System.Net.Http.HttpMethod("POST");
4273+
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
4274+
4275+
var urlBuilder_ = new System.Text.StringBuilder();
4276+
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
4277+
// Operation Path: "internal/v1/hub/tags/add"
4278+
urlBuilder_.Append("internal/v1/hub/tags/add");
4279+
4280+
PrepareRequest(client_, request_, urlBuilder_);
4281+
4282+
var url_ = urlBuilder_.ToString();
4283+
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
4284+
4285+
PrepareRequest(client_, request_, url_);
4286+
4287+
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
4288+
var disposeResponse_ = true;
4289+
try
4290+
{
4291+
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
4292+
foreach (var item_ in response_.Headers)
4293+
headers_[item_.Key] = item_.Value;
4294+
if (response_.Content != null && response_.Content.Headers != null)
4295+
{
4296+
foreach (var item_ in response_.Content.Headers)
4297+
headers_[item_.Key] = item_.Value;
4298+
}
4299+
4300+
ProcessResponse(client_, response_);
4301+
4302+
var status_ = (int)response_.StatusCode;
4303+
if (status_ == 200)
4304+
{
4305+
var objectResponse_ = await ReadObjectResponseAsync<ActionResult>(response_, headers_, cancellationToken).ConfigureAwait(false);
4306+
if (objectResponse_.Object == null)
4307+
{
4308+
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
4309+
}
4310+
return objectResponse_.Object;
4311+
}
4312+
else
4313+
{
4314+
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
4315+
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
4316+
}
4317+
}
4318+
finally
4319+
{
4320+
if (disposeResponse_)
4321+
response_.Dispose();
4322+
}
4323+
}
4324+
}
4325+
finally
4326+
{
4327+
if (disposeClient_)
4328+
client_.Dispose();
4329+
}
4330+
}
4331+
41604332
/// <summary>
41614333
/// Request a challenge response
41624334
/// </summary>

src/Certify.Server/Certify.Server.HubService/Services/CertifyDirectHubService.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ private ServiceControllers.SystemController _systemController(AuthContext authCo
6363
return controller;
6464
}
6565

66+
private ServiceControllers.TagController _tagController(AuthContext authContext)
67+
{
68+
var controller = new ServiceControllers.TagController(_certifyManager);
69+
controller.SetCurrentAuthContext(authContext);
70+
return controller;
71+
}
72+
6673
public Task<Preferences> GetPreferences(AuthContext? authContext = null) => Task.FromResult(new ServiceControllers.PreferencesController(_certifyManager).GetPreferences());
6774

6875
public Task<ActionResult> AddSecurityPrinciple(SecurityPrinciple principle, AuthContext authContext) => _accessController(authContext).AddSecurityPrinciple(principle);
@@ -163,6 +170,10 @@ private ServiceControllers.SystemController _systemController(AuthContext authCo
163170
public Task<ActionResult> JoinManagementHub(HubJoiningClientSecret hubJoiningClientSecret, AuthContext? authContext = null) => throw new NotImplementedException();
164171
public Task<ActionResult> CheckManagementHubCredentials(HubJoiningClientSecret hubJoiningClientSecret, AuthContext? authContext = null) => throw new NotImplementedException();
165172
public Task<ActionResult> CheckManagementHubConnectionStatus(AuthContext? authContext = null) => throw new NotImplementedException();
173+
174+
public Task<ActionResult> AddHubItemTag(ItemTag tag, AuthContext authContext) => _tagController(authContext).AddTag(tag);
175+
public Task<ICollection<ItemTag>> GetHubItemTags(AuthContext authContext) => _tagController(authContext).GetTags();
176+
166177
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
167178
}
168179
}

src/Certify.SourceGenerators/ApiMethods.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,30 @@ public static List<GeneratedAPI> GetApiDefinitions()
725725
{ "prefs", "Certify.Models.Preferences" }
726726
},
727727
RequiredPermissions = [new(ResourceTypes.System, StandardResourceActions.SystemCoreSettingsUpdate)]
728-
}
728+
},
729+
new()
730+
{
731+
OperationName = "GetHubItemTags",
732+
OperationMethod = HttpGet,
733+
Comment = "Get hub item tags",
734+
PublicAPIController = "Hub",
735+
PublicAPIRoute = "tags/list",
736+
ServiceAPIRoute = "tags/list",
737+
ReturnType = "ICollection<ItemTag>",
738+
RequiredPermissions = [new(ResourceTypes.Tag, StandardResourceActions.TagList)]
739+
},
740+
new()
741+
{
742+
OperationName = "AddHubItemTag",
743+
OperationMethod = HttpPost,
744+
Comment = "Add hub item tag",
745+
PublicAPIController = "Hub",
746+
PublicAPIRoute = "tags/add",
747+
ServiceAPIRoute = "tags/add",
748+
ReturnType = actionResultTypeName,
749+
Params = new Dictionary<string, string> { { "tag", GetFormattedTypeName(typeof(ItemTag)) } },
750+
RequiredPermissions = [new(ResourceTypes.Tag, StandardResourceActions.TagAdd)]
751+
},
729752
};
730753
}
731754
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
using Certify.Management;
5+
using Certify.Models.Hub;
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
8+
namespace Certify.Core.Tests.Unit
9+
{
10+
[TestClass]
11+
public class HubItemTagsTests
12+
{
13+
private CertifyManager _manager;
14+
private MemoryObjectStore _store;
15+
16+
[TestInitialize]
17+
public void Setup()
18+
{
19+
_store = new MemoryObjectStore();
20+
_manager = new CertifyManager();
21+
typeof(CertifyManager)
22+
.GetField("_configStore", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
23+
.SetValue(_manager, _store);
24+
}
25+
26+
[TestMethod]
27+
public async Task AddHubItemTags_AddsTags()
28+
{
29+
var tags = new List<ItemTag>
30+
{
31+
new ItemTag("item1", "type1", "tag1", "value1"),
32+
new ItemTag("item2", "type2", "tag2", "value2")
33+
};
34+
35+
var result = await _manager.AddHubItemTags(tags);
36+
Assert.IsTrue(result.IsSuccess);
37+
38+
var allTags = await _manager.GetAllHubItemTags();
39+
Assert.AreEqual(2, allTags.Count);
40+
}
41+
42+
[TestMethod]
43+
public async Task RemoveHubItemTags_RemovesTags()
44+
{
45+
var tag = new ItemTag("item1", "type1", "tag1", "value1");
46+
await _manager.AddHubItemTags(new List<ItemTag> { tag });
47+
var allTags = await _manager.GetAllHubItemTags();
48+
Assert.AreEqual(1, allTags.Count);
49+
50+
var result = await _manager.RemoveHubItemTags(new List<string> { allTags.First().Id });
51+
Assert.IsTrue(result.IsSuccess);
52+
53+
allTags = await _manager.GetAllHubItemTags();
54+
Assert.AreEqual(0, allTags.Count);
55+
}
56+
57+
[TestMethod]
58+
public async Task GetAllHubItemTags_ReturnsAllTags()
59+
{
60+
await _manager.AddHubItemTags(new List<ItemTag>
61+
{
62+
new ItemTag("item1", "type1", "tag1", "value1"),
63+
new ItemTag("item2", "type2", "tag2", "value2")
64+
});
65+
var allTags = await _manager.GetAllHubItemTags();
66+
Assert.AreEqual(2, allTags.Count);
67+
}
68+
69+
[TestMethod]
70+
public async Task GetHubItemTags_ReturnsTagsForItem()
71+
{
72+
await _manager.AddHubItemTags(new List<ItemTag>
73+
{
74+
new ItemTag("item1", "type1", "tag1", "value1"),
75+
new ItemTag("item1", "type1", "tag2", "value2"),
76+
new ItemTag("item2", "type2", "tag3", "value3")
77+
});
78+
var tagsForItem1 = await _manager.GetHubItemTags("item1", "type1");
79+
Assert.AreEqual(2, tagsForItem1.Count);
80+
Assert.IsTrue(tagsForItem1.All(t => t.TaggedItemId == "item1"));
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)