Skip to content

Commit

Permalink
Feature/resourceregistryserialization (#11173)
Browse files Browse the repository at this point in the history
* Fixed serialization

* Fixed enum

* Fixed formatting.
Added Competent authority on save

* Code smell

* Code smell
  • Loading branch information
TheTechArch authored Sep 21, 2023
1 parent 5103a0b commit c02de0a
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 24 deletions.
2 changes: 2 additions & 0 deletions backend/src/Designer/Configuration/CacheSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
public class CacheSettings
{
public int DataNorgeApiCacheTimeout { get; set; }

public int OrgListCacheTimeout { get; set; }
}
}
50 changes: 47 additions & 3 deletions backend/src/Designer/Controllers/ResourceAdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Altinn.Authorization.ABAC.Xacml;
using Altinn.ResourceRegistry.Core.Enums.Altinn2;
using Altinn.ResourceRegistry.Core.Models;
using Altinn.ResourceRegistry.Core.Models.Altinn2;
using Altinn.Studio.Designer.Configuration;
using Altinn.Studio.Designer.Helpers;
Expand All @@ -30,15 +31,17 @@ public class ResourceAdminController : ControllerBase
private readonly IMemoryCache _memoryCache;
private readonly CacheSettings _cacheSettings;
private readonly IAltinn2MetadataClient _altinn2MetadataClient;
private readonly IOrgService _orgService;

public ResourceAdminController(IGitea gitea, IRepository repository, IResourceRegistryOptions resourceRegistryOptions, IMemoryCache memoryCache, IOptions<CacheSettings> cacheSettings, IAltinn2MetadataClient altinn2MetadataClient)
public ResourceAdminController(IGitea gitea, IRepository repository, IResourceRegistryOptions resourceRegistryOptions, IMemoryCache memoryCache, IOptions<CacheSettings> cacheSettings, IAltinn2MetadataClient altinn2MetadataClient, IOrgService orgService)
{
_giteaApi = gitea;
_repository = repository;
_resourceRegistryOptions = resourceRegistryOptions;
_memoryCache = memoryCache;
_cacheSettings = cacheSettings.Value;
_altinn2MetadataClient = altinn2MetadataClient;
_orgService = orgService;
}

[HttpGet]
Expand Down Expand Up @@ -158,15 +161,17 @@ public ActionResult GetValidateResource(string org, string repository, string id

[HttpPut]
[Route("designer/api/{org}/resources/updateresource/{id}")]
public ActionResult UpdateResource(string org, string id, [FromBody] ServiceResource resource)
public async Task<ActionResult> UpdateResource(string org, string id, [FromBody] ServiceResource resource)
{
resource.HasCompetentAuthority = await GetCompetentAuthorityFromOrg(org);
return _repository.UpdateServiceResource(org, id, resource);
}

[HttpPost]
[Route("designer/api/{org}/resources/addresource")]
public ActionResult<ServiceResource> AddResource(string org, [FromBody] ServiceResource resource)
public async Task<ActionResult<ServiceResource>> AddResource(string org, [FromBody] ServiceResource resource)
{
resource.HasCompetentAuthority = await GetCompetentAuthorityFromOrg(org);
return _repository.AddServiceResource(org, resource);
}

Expand Down Expand Up @@ -333,5 +338,44 @@ public async Task<ActionResult> PublishResource(string org, string repository, s
return new StatusCodeResult(400);
}
}

private async Task<CompetentAuthority> GetCompetentAuthorityFromOrg(string org)
{
Org organization = await GetOrg(org);
if (organization == null)
{
return null;
}
return new CompetentAuthority() { Name = organization.Name, Organization = organization.Orgnr, Orgcode = org };
}

private async Task<Org> GetOrg(string org)
{
OrgList orgList = await GetOrgList();

if (orgList.Orgs.TryGetValue(org, out Org organization))
{
return organization;
}

return null;
}

private async Task<OrgList> GetOrgList()
{
string cacheKey = "orglist";
if (!_memoryCache.TryGetValue(cacheKey, out OrgList orgList))
{
orgList = await _orgService.GetOrgList();

var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.High)
.SetAbsoluteExpiration(new TimeSpan(0, _cacheSettings.OrgListCacheTimeout, 0));

_memoryCache.Set(cacheKey, orgList, cacheEntryOptions);
}

return orgList;
}
}
}
4 changes: 4 additions & 0 deletions backend/src/Designer/Designer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
<Watch Remove="Models\ListviewServiceResource.cs" />
<Watch Remove="Models\LosTerm.cs" />
<Watch Remove="Models\LosTerms.cs" />
<Watch Remove="Models\Org.cs" />
<Watch Remove="Models\OrgList.cs" />
<Watch Remove="Models\ResourcePartyType.cs" />
<Watch Remove="Models\ResourceReference.cs" />
<Watch Remove="Models\ResourceVersionInfo.cs" />
Expand All @@ -103,10 +105,12 @@
<Watch Remove="RepositoryClient\Model\ContentsResponse.cs" />
<Watch Remove="RepositoryClient\Model\FileLinksResponse.cs" />
<Watch Remove="RepositoryClient\Model\GiteaRepoCommitStats.cs" />
<Watch Remove="Services\Implementation\OrgService.cs" />
<Watch Remove="Services\Implementation\PolicyOptionsService.cs" />
<Watch Remove="Services\Implementation\ResourceRegistryAdminService.cs" />
<Watch Remove="Services\Implementation\ResourceService.cs" />
<Watch Remove="Services\Implementation\SourceControlLoggingDecorator.cs" />
<Watch Remove="Services\Interfaces\IOrgService.cs" />
<Watch Remove="Services\Interfaces\IResourceRegistry.cs" />
<Watch Remove="Services\Interfaces\IPolicyOptions.cs" />
<Watch Remove="Services\Interfaces\IResourceRegistryAdmin.cs" />
Expand Down
2 changes: 2 additions & 0 deletions backend/src/Designer/Enums/ResourcePartyType.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Runtime.Serialization;
using System.Text.Json.Serialization;

namespace Altinn.Studio.Designer.Enums
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ResourcePartyType
{
[EnumMember(Value = "PrivatePerson")]
Expand Down
1 change: 1 addition & 0 deletions backend/src/Designer/Infrastructure/ServiceRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static IServiceCollection RegisterServiceImplementations(this IServiceCol
services.AddTransient<ILanguagesService, LanguagesService>();
services.AddTransient<ITextsService, TextsService>();
services.AddTransient<IEnvironmentsService, EnvironmentsService>();
services.AddHttpClient<IOrgService, OrgService>();
services.AddTransient<IAppDevelopmentService, AppDevelopmentService>();
services.AddTransient<IPreviewService, PreviewService>();
services.AddTransient<IResourceRegistry, ResourceRegistryService>();
Expand Down
37 changes: 37 additions & 0 deletions backend/src/Designer/Models/Org.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Altinn.ResourceRegistry.Core.Models
{
/// <summary>
/// Describes an organization
/// </summary>
public class Org
{
/// <summary>
/// Name of organization. With lanugage support
/// </summary>
[JsonProperty("name")]
public Dictionary<string, string> Name { get; set; }

/// <summary>
/// The logo
/// </summary>
public string Logo { get; set; }

/// <summary>
/// The organization number
/// </summary>
public string Orgnr { get; set; }

/// <summary>
/// The homepage
/// </summary>
public string Homepage { get; set; }

/// <summary>
/// The environments available for the organzation
/// </summary>
public List<string> Environments { get; set; }
}
}
17 changes: 17 additions & 0 deletions backend/src/Designer/Models/OrgList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Altinn.ResourceRegistry.Core.Models;
using Newtonsoft.Json;

namespace Altinn.Studio.Designer.Models
{
/// <summary>
/// Defines a list of orgs
/// </summary>
public class OrgList
{
/// <summary>
/// Dictionary of orgs
/// </summary>
public Dictionary<string, Org> Orgs { get; set; }
}
}
38 changes: 38 additions & 0 deletions backend/src/Designer/Services/Implementation/OrgService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Net.Http;
using System.Threading.Tasks;
using Altinn.Studio.Designer.Configuration;
using Altinn.Studio.Designer.Models;
using Altinn.Studio.Designer.Services.Interfaces;

namespace Altinn.Studio.Designer.Services.Implementation
{
/// <summary>
/// Client responsible for collection
/// </summary>
public class OrgService : IOrgService
{
private readonly HttpClient _client;
private readonly GeneralSettings _generalSettings;

/// <summary>
/// Default constructor
/// </summary>
public OrgService(HttpClient client, GeneralSettings generalSettingsOptions)
{
_client = client;
_generalSettings = generalSettingsOptions;
}

/// <summary>
/// Returns configured org list
/// </summary>
public async Task<OrgList> GetOrgList()
{
HttpResponseMessage response = await _client.GetAsync(_generalSettings.OrganizationsUrl);
response.EnsureSuccessStatusCode();
string orgListString = await response.Content.ReadAsStringAsync();
OrgList orgList = System.Text.Json.JsonSerializer.Deserialize<OrgList>(orgListString, new System.Text.Json.JsonSerializerOptions() { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase });
return orgList;
}
}
}
10 changes: 6 additions & 4 deletions backend/src/Designer/Services/Implementation/RepositorySI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml;
using Altinn.Authorization.ABAC.Utils;
Expand Down Expand Up @@ -40,6 +41,7 @@ public class RepositorySI : IRepository
private readonly IApplicationMetadataService _applicationMetadataService;
private readonly ITextsService _textsService;
private readonly IResourceRegistry _resourceRegistryService;
private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase, WriteIndented = true };

/// <summary>
/// Initializes a new instance of the <see cref="RepositorySI"/> class
Expand Down Expand Up @@ -762,7 +764,7 @@ public List<ServiceResource> GetServiceResources(string org, string repository,
foreach (FileSystemObject resourceFile in resourceFiles)
{
string jsonString = File.ReadAllText($"{repopath}/{resourceFile.Path}");
ServiceResource serviceResource = JsonConvert.DeserializeObject<ServiceResource>(jsonString);
ServiceResource serviceResource = System.Text.Json.JsonSerializer.Deserialize<ServiceResource>(jsonString, _serializerOptions);

if (serviceResource != null)
{
Expand All @@ -784,11 +786,11 @@ public ActionResult UpdateServiceResource(string org, string id, ServiceResource
foreach (FileSystemObject resourceFile in resourceFiles)
{
string jsonString = File.ReadAllText($"{repopath}/{resourceFile.Path}");
ServiceResource serviceResource = JsonConvert.DeserializeObject<ServiceResource>(jsonString);
ServiceResource serviceResource = System.Text.Json.JsonSerializer.Deserialize<ServiceResource>(jsonString, _serializerOptions);

if (serviceResource != null && serviceResource.Identifier == updatedResource.Identifier)
{
string updatedResourceString = JsonConvert.SerializeObject(updatedResource);
string updatedResourceString = System.Text.Json.JsonSerializer.Serialize(updatedResource, _serializerOptions);
File.WriteAllText($"{repopath}/{resourceFile.Path}", updatedResourceString);
return new StatusCodeResult(201);
}
Expand All @@ -811,7 +813,7 @@ public ActionResult AddServiceResource(string org, ServiceResource newResource)
{
string repopath = _settings.GetServicePath(org, repository, AuthenticationHelper.GetDeveloperUserName(_httpContextAccessor.HttpContext));
string fullPathOfNewResource = Path.Combine(repopath, newResource.Identifier.AsFileName(), string.Format("{0}_resource.json", newResource.Identifier));
string newResourceJson = JsonConvert.SerializeObject(newResource);
string newResourceJson = System.Text.Json.JsonSerializer.Serialize(newResource, _serializerOptions);
Directory.CreateDirectory(Path.Combine(repopath, newResource.Identifier.AsFileName()));
File.WriteAllText(fullPathOfNewResource, newResourceJson);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Altinn.ApiClients.Maskinporten.Interfaces;
using Altinn.ApiClients.Maskinporten.Models;
using Altinn.Studio.Designer.Configuration;
using Altinn.Studio.Designer.Helpers;
using Altinn.Studio.Designer.Models;
using Altinn.Studio.Designer.Services.Interfaces;
using Altinn.Studio.Designer.TypedHttpClients.AzureDevOps.Enums;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace Altinn.Studio.Designer.Services.Implementation
{
Expand All @@ -25,6 +28,7 @@ public class ResourceRegistryService : IResourceRegistry
private readonly PlatformSettings _platformSettings;
private readonly ResourceRegistryIntegrationSettings _resourceRegistrySettings;
private readonly ResourceRegistryMaskinportenIntegrationSettings _maskinportenIntegrationSettings;
private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase, WriteIndented = true };

public ResourceRegistryService()
{
Expand Down Expand Up @@ -71,10 +75,35 @@ public async Task<ActionResult> PublishServiceResource(ServiceResource serviceRe
fullWritePolicyToResourceRegistryUrl = $"{_platformSettings.ResourceRegistryDefaultBaseUrl}{_platformSettings.ResourceRegistryUrl}/{serviceResource.Identifier}/policy";
}

string serviceResourceString = JsonConvert.SerializeObject(serviceResource);
string serviceResourceString = System.Text.Json.JsonSerializer.Serialize(serviceResource, _serializerOptions);
_httpClientFactory.CreateClient("myHttpClient");
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken);

HttpResponseMessage getResourceResponse = await _httpClient.GetAsync(getResourceRegistryUrl);

HttpResponseMessage response;

if (getResourceResponse.IsSuccessStatusCode && getResourceResponse.StatusCode.Equals(HttpStatusCode.OK))
{
string putRequest = $"{publishResourceToResourceRegistryUrl}/{serviceResource.Identifier}";
using (StringContent putContent = new StringContent(serviceResourceString, Encoding.UTF8, "application/json"))
{
response = await _httpClient.PutAsync(putRequest, putContent);
}
}
else
{
using (StringContent postContent = new StringContent(serviceResourceString, Encoding.UTF8, "application/json"))
{
response = await _httpClient.PostAsync(publishResourceToResourceRegistryUrl, postContent);
}
}

if (!response.IsSuccessStatusCode)
{
return await GetPublishResponse(response);
}

if (policyPath != null)
{
MultipartFormDataContent content = new MultipartFormDataContent();
Expand Down Expand Up @@ -125,26 +154,15 @@ public async Task<ActionResult> PublishServiceResource(ServiceResource serviceRe
}
}

HttpResponseMessage getResourceResponse = await _httpClient.GetAsync(getResourceRegistryUrl);

if (getResourceResponse.IsSuccessStatusCode)
{
string putRequest = $"{publishResourceToResourceRegistryUrl}/{serviceResource.Identifier}";
HttpResponseMessage putResponse = await _httpClient.PutAsync(putRequest, new StringContent(serviceResourceString, Encoding.UTF8, "application/json"));
return putResponse.IsSuccessStatusCode ? new StatusCodeResult(201) : new StatusCodeResult(400);
}

HttpResponseMessage response = await _httpClient.PostAsync(publishResourceToResourceRegistryUrl, new StringContent(serviceResourceString, Encoding.UTF8, "application/json"));

return GetPublishResponse(response);
return await GetPublishResponse(response);
}

private async Task<TokenResponse> GetBearerTokenFromMaskinporten()
{
return await _maskinPortenService.GetToken(_maskinportenClientDefinition.ClientSettings.EncodedJwk, _maskinportenClientDefinition.ClientSettings.Environment, _maskinportenClientDefinition.ClientSettings.ClientId, _maskinportenClientDefinition.ClientSettings.Scope, _maskinportenClientDefinition.ClientSettings.Resource, _maskinportenClientDefinition.ClientSettings.ConsumerOrgNo);
}

private StatusCodeResult GetPublishResponse(HttpResponseMessage response)
private async Task<ActionResult> GetPublishResponse(HttpResponseMessage response)
{
if (response.StatusCode == HttpStatusCode.Created)
{
Expand All @@ -156,7 +174,16 @@ private StatusCodeResult GetPublishResponse(HttpResponseMessage response)
}
else
{
return new StatusCodeResult(400);
string responseContent = await response.Content.ReadAsStringAsync();
try
{
ProblemDetails problems = JsonSerializer.Deserialize<ProblemDetails>(responseContent);
return new ObjectResult(problems) { StatusCode = (int)response.StatusCode };
}
catch (Exception)
{
return new ContentResult() { Content = responseContent, StatusCode = (int)response.StatusCode };
}
}
}

Expand Down
Loading

0 comments on commit c02de0a

Please sign in to comment.