Skip to content

Commit

Permalink
feat: add syndication to oslo api
Browse files Browse the repository at this point in the history
  • Loading branch information
ArneD authored Jun 14, 2024
1 parent 4c39cd7 commit 71a29f3
Show file tree
Hide file tree
Showing 7 changed files with 659 additions and 1 deletion.
2 changes: 2 additions & 0 deletions PostalRegistry.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
Expand Down Expand Up @@ -65,4 +66,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECpp_002EDaemon_002EInlayHints_002EParameterHints_002ECppParameterNameHintsOptionsOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECSharp_002EParameterNameHints_002ECSharpParameterNameHintsOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EVB_002EParameterNameHints_002EVBParameterNameHintsOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
20 changes: 20 additions & 0 deletions src/PostalRegistry.Api.Oslo/Convertors/PostalInformationStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace PostalRegistry.Api.Oslo.Convertors
{
using Be.Vlaanderen.Basisregisters.GrAr.Legacy;

public static class PostalInformationStatusExtensions
{
public static PostInfoStatus ConvertFromPostalInformationStatus(this PostalInformationStatus postalInformationStatus)
{
switch (postalInformationStatus)
{
case PostalInformationStatus.Retired:
return PostInfoStatus.Gehistoreerd;

default:
case PostalInformationStatus.Current:
return PostInfoStatus.Gerealiseerd;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace PostalRegistry.Api.Oslo.Infrastructure
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Be.Vlaanderen.Basisregisters.Api.Syndication;
using Microsoft.Extensions.Configuration;
using Microsoft.SyndicationFeed;
using Microsoft.SyndicationFeed.Atom;

public static class AtomFeedConfigurationBuilder
{
public static AtomFeedConfiguration CreateFrom(IConfigurationSection configuration, DateTimeOffset lastUpdated)
{
return new AtomFeedConfiguration(
configuration["Id"],
configuration["Title"],
configuration["Subtitle"],
configuration["GeneratorTitle"],
configuration["GeneratorUri"],
Assembly.GetEntryAssembly().GetName().Version.ToString(),
configuration["Rights"],
lastUpdated,
new SyndicationPerson(configuration["AuthorName"], configuration["AuthorEmail"], AtomContributorTypes.Author),
new SyndicationLink(new Uri(configuration["Self"]), AtomLinkTypes.Self),
new List<SyndicationLink>(),
configuration
.GetSection("Related")
.GetChildren()
.Select(c =>
new SyndicationLink(new Uri(c.Value), AtomLinkTypes.Related))
.ToList()
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@ namespace PostalRegistry.Api.Oslo.PostalInformation
{
using System;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Asp.Versioning;
using Be.Vlaanderen.Basisregisters.Api;
using Be.Vlaanderen.Basisregisters.Api.Exceptions;
using Be.Vlaanderen.Basisregisters.Api.Search;
using Be.Vlaanderen.Basisregisters.Api.Search.Filtering;
using Be.Vlaanderen.Basisregisters.Api.Search.Pagination;
using Be.Vlaanderen.Basisregisters.Api.Search.Sorting;
using Be.Vlaanderen.Basisregisters.Api.Syndication;
using Be.Vlaanderen.Basisregisters.GrAr.Common;
using Be.Vlaanderen.Basisregisters.GrAr.Common.Syndication;
using Be.Vlaanderen.Basisregisters.GrAr.Legacy;
using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Gemeente;
using Be.Vlaanderen.Basisregisters.GrAr.Legacy.PostInfo;
using Convertors;
using Infrastructure;
using Infrastructure.Options;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.SyndicationFeed;
using Microsoft.SyndicationFeed.Atom;
using Nuts;
using Projections.Legacy;
using Projections.Syndication;
Expand Down Expand Up @@ -196,6 +205,92 @@ public async Task<IActionResult> Count(
});
}

/// <summary>
/// Vraag een lijst met wijzigingen van postinfo op.
/// </summary>
/// <param name="configuration"></param>
/// <param name="context"></param>
/// <param name="responseOptions"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("sync")]
[Produces("text/xml")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
[SwaggerResponseExample(StatusCodes.Status200OK, typeof(PostalInformationSyndicationResponseExamples))]
[SwaggerResponseExample(StatusCodes.Status400BadRequest, typeof(BadRequestResponseExamples))]
[SwaggerResponseExample(StatusCodes.Status500InternalServerError, typeof(InternalServerErrorResponseExamples))]
public async Task<IActionResult> Sync(
[FromServices] IConfiguration configuration,
[FromServices] LegacyContext context,
[FromServices] IOptions<ResponseOptions> responseOptions,
CancellationToken cancellationToken = default)
{
var filtering = Request.ExtractFilteringRequest<PostalInformationSyndicationFilter>();
var sorting = Request.ExtractSortingRequest();
var pagination = Request.ExtractPaginationRequest();

var lastFeedUpdate = await context
.PostalInformationSyndication
.AsNoTracking()
.OrderByDescending(item => item.Position)
.Select(item => item.SyndicationItemCreatedAt)
.FirstOrDefaultAsync(cancellationToken);

if (lastFeedUpdate == default)
lastFeedUpdate = new DateTimeOffset(2020, 1, 1, 0, 0, 0, TimeSpan.Zero);

var pagedPostalInformationSet =
new PostalInformationSyndicationQuery(
context,
filtering.Filter?.Embed)
.Fetch(filtering, sorting, pagination);

return new ContentResult
{
Content = await BuildAtomFeed(lastFeedUpdate, pagedPostalInformationSet, responseOptions, configuration),
ContentType = MediaTypeNames.Text.Xml,
StatusCode = StatusCodes.Status200OK
};
}

private static async Task<string> BuildAtomFeed(
DateTimeOffset lastFeedUpdate,
PagedQueryable<PostalInformationSyndicationQueryResult> pagedPostalInfoItems,
IOptions<ResponseOptions> responseOptions,
IConfiguration configuration)
{
var sw = new StringWriterWithEncoding(Encoding.UTF8);

using (var xmlWriter = XmlWriter.Create(sw, new XmlWriterSettings { Async = true, Indent = true, Encoding = sw.Encoding }))
{
var formatter = new AtomFormatter(null, xmlWriter.Settings) { UseCDATA = true };
var writer = new AtomFeedWriter(xmlWriter, null, formatter);
var syndicationConfiguration = configuration.GetSection("Syndication");
var atomFeedConfig = AtomFeedConfigurationBuilder.CreateFrom(syndicationConfiguration, lastFeedUpdate);

await writer.WriteDefaultMetadata(atomFeedConfig);

var postalInfos = pagedPostalInfoItems.Items.ToList();

var nextFrom = postalInfos.Any()
? postalInfos.Max(x => x.Position) + 1
: (long?) null;

var nextUri = BuildNextSyncUri(pagedPostalInfoItems.PaginationInfo.Limit, nextFrom, syndicationConfiguration["NextUri"]);
if (nextUri != null)
await writer.Write(new SyndicationLink(nextUri, GrArAtomLinkTypes.Next));

foreach (var postalInfo in postalInfos)
await writer.WritePostalInfo(responseOptions, formatter, syndicationConfiguration["Category"], postalInfo);

xmlWriter.Flush();
}

return sw.ToString();
}

private static Uri? BuildNextUri(PaginationInfo paginationInfo, int itemsInCollection, string nextUrlBase)
{
var offset = paginationInfo.Offset;
Expand All @@ -206,6 +301,13 @@ public async Task<IActionResult> Count(
: null;
}

private static Uri? BuildNextSyncUri(int limit, long? from, string nextUrlBase)
{
return from.HasValue
? new Uri(string.Format(nextUrlBase, from.Value, limit))
: null;
}

private async Task<PostinfoDetailGemeente?> GetPostinfoDetailGemeente(
SyndicationContext syndicationContext,
string? nisCode,
Expand Down
Loading

0 comments on commit 71a29f3

Please sign in to comment.