Skip to content

Commit 0c76a8a

Browse files
committed
add outbox data for request service
1 parent b55f5d8 commit 0c76a8a

File tree

4 files changed

+81
-21
lines changed

4 files changed

+81
-21
lines changed

src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Api.ServiceOwner/Controllers/RequestController.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ public async Task<IActionResult> CreateRequest([FromBody] CreateServiceOwnerRequ
6969
{
7070
ValidationErrorBuilder errorBuilder = default;
7171

72-
var fromResult = await GetEntity(input.Connection.From, "BODY/connection.from", ct);
72+
var fromResult = await GetEntity(input.Connection.From, "connection/from", ct);
7373
if (fromResult.IsProblem)
7474
{
7575
return fromResult.Problem.ToActionResult();
7676
}
7777

78-
var toResult = await GetEntity(input.Connection.To, "BODY/connection.to", ct);
79-
if (toResult.IsProblem)
80-
{
81-
return toResult.Problem.ToActionResult();
78+
var toResult = await GetEntity(input.Connection.To, "connection/to", ct);
79+
if (toResult.IsProblem)
80+
{
81+
return toResult.Problem.ToActionResult();
8282
}
8383

8484
var from = fromResult.Value;
@@ -91,12 +91,12 @@ public async Task<IActionResult> CreateRequest([FromBody] CreateServiceOwnerRequ
9191

9292
if (input.Resource.HasValue() && resource == null)
9393
{
94-
errorBuilder.Add(ValidationErrorDescriptors.RequestedResourceNotFound, $"BODY/resource", [new("resource", $"Urn {input.Resource.Urn} is not valid")]);
94+
errorBuilder.Add(ValidationErrorDescriptors.RequestedResourceNotFound, $"resource", [new("resource", $"Urn {input.Resource.Urn} is not valid")]);
9595
}
9696

9797
if (input.Package.HasValue() && package == null)
9898
{
99-
errorBuilder.Add(ValidationErrorDescriptors.RequestedPackageNotFound, $"BODY/package", [new("package", $"Urn {input.Package.Urn} is not valid")]);
99+
errorBuilder.Add(ValidationErrorDescriptors.RequestedPackageNotFound, $"package", [new("package", $"Urn {input.Package.Urn} is not valid")]);
100100
}
101101

102102
if (errorBuilder.TryBuild(out var problem))
@@ -163,14 +163,14 @@ private async Task<Result<Entity>> GetEntity(string urn, string paramName, Cance
163163
errorBuilder.Add(ValidationErrorDescriptors.NotFound, $"$QUERY/{paramName}", [new(paramName, $"Entity not found with matcing urn '{urn}'")]);
164164
}
165165

166-
if (errorBuilder.TryBuild(out var problem1))
166+
if (errorBuilder.TryBuild(out problem))
167167
{
168-
return problem1;
168+
return problem;
169169
}
170170

171171
return entity;
172172
}
173-
173+
174174
private static bool ValidUrn(string urn) => ValidUrns.Any(t => urn.StartsWith(t));
175175

176176
private static string[] ValidUrns => ["urn:altinn:person:identifier-no", "urn:altinn:organization:identifier-no"];

src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Core/Outbox/ResourceRequestPendingNotificationHandler.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ public class ResourceRequestPendingNotificationHandler(IAltinnNotification notif
1515
{
1616
public async Task Handle(OutboxMessage message, CancellationToken cancellationToken)
1717
{
18-
var (recipient, sender, resources) = await GetContext(message, cancellationToken);
18+
var (recipient, sender, idempotencyId, resources) = await GetContext(message, cancellationToken);
1919

2020
var response = await notification.Send(
2121
new()
2222
{
23-
IdempotencyId = $"auth_resource_request_accept_{recipient.Id}",
23+
IdempotencyId = idempotencyId,
2424
Recipient = CreateRecipient(recipient, sender, resources),
2525
RequestedSendTime = DateTime.UtcNow,
2626
},
@@ -32,7 +32,7 @@ public async Task Handle(OutboxMessage message, CancellationToken cancellationTo
3232
}
3333
}
3434

35-
private async Task<(Entity Recipient, Entity Sender, IEnumerable<string> Resources)> GetContext(OutboxMessage message, CancellationToken cancellationToken)
35+
private async Task<(Entity Recipient, Entity Sender, string IdempotencyId, IEnumerable<string> Resources)> GetContext(OutboxMessage message, CancellationToken cancellationToken)
3636
{
3737
var content = JsonSerializer.Deserialize<List<ResourceRequestPendingNotificationMessage>>(message.Data);
3838
if (content is null || content.Count == 0)
@@ -69,6 +69,7 @@ public async Task Handle(OutboxMessage message, CancellationToken cancellationTo
6969
return (
7070
entityRecipient,
7171
entitySender,
72+
$"auth_resource_request_pending_{recipient.Key}_{sender.Key}_{content.OrderBy(m => m.ExpectedDeliveredAt).First().ExpectedDeliveredAt.Ticks}",
7273
content.Select(m => m.Resource).Distinct()
7374
);
7475
}
@@ -163,5 +164,5 @@ public class ResourceRequestPendingNotificationMessage
163164
/// <summary>
164165
/// Used for creating a unique idempotency key and external ref id
165166
/// </summary>
166-
public DateTime RefId { get; set; }
167+
public DateTime ExpectedDeliveredAt { get; set; }
167168
}

src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Core/Services/RequestService.cs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using Altinn.AccessManagement.Core.Errors;
1+
using System.Diagnostics;
2+
using System.Transactions;
3+
using Altinn.AccessManagement.Core.Errors;
4+
using Altinn.AccessMgmt.Core.Outbox;
25
using Altinn.AccessMgmt.Core.Services.Contracts;
36
using Altinn.AccessMgmt.Core.Utils;
47
using Altinn.AccessMgmt.PersistenceEF.Contexts;
@@ -7,6 +10,7 @@
710
using Altinn.Authorization.Api.Contracts.AccessManagement.Request;
811
using Altinn.Authorization.ProblemDetails;
912
using Microsoft.EntityFrameworkCore;
13+
using Swashbuckle.AspNetCore.SwaggerGen;
1014
using static System.Runtime.InteropServices.JavaScript.JSType;
1115

1216
namespace Altinn.AccessMgmt.Core.Services;
@@ -48,7 +52,7 @@ public async Task<Result<RequestDto>> GetRequest(Guid requestId, CancellationTok
4852

4953
return problems;
5054
}
51-
55+
5256
/// <inheritdoc/>
5357
public async Task<Result<IEnumerable<RequestDto>>> GetRequests(Guid? fromId, Guid? toId, IEnumerable<RequestStatus> status, DateTimeOffset? after, CancellationToken ct = default)
5458
{
@@ -118,7 +122,7 @@ public async Task<Result<RequestDto>> UpdateRequest(Guid partyUuid, Guid request
118122
}
119123

120124
var request = requestResult.Value;
121-
125+
122126
if (request.Connection.From.Id != partyUuid)
123127
{
124128
errorBuilder.Add(ValidationErrors.RequestNotFound, "$QUERY/requestId", [new("RequestId", $"Request {requestId} does not exists")]);
@@ -205,7 +209,7 @@ private async Task<IEnumerable<RequestAssignmentResource>> GetRequestAssignmentR
205209
.WhereIf(after.HasValue, r => r.Audit_ValidFrom >= after.Value)
206210
.ToListAsync(cancellationToken: ct);
207211
}
208-
212+
209213
private async Task<IEnumerable<RequestAssignmentPackage>> GetRequestAssignmentPackage(Guid? fromId, Guid? toId, IEnumerable<RequestStatus> status, DateTimeOffset? after, CancellationToken ct)
210214
{
211215
if (!fromId.HasValue && !toId.HasValue)
@@ -260,7 +264,54 @@ private async Task<Result<RequestDto>> CreateRequestAssignmentResource(Guid assi
260264
AssignmentId = assignmentId,
261265
ResourceId = resourceId
262266
};
267+
263268
db.RequestAssignmentResources.Add(request);
269+
await db.UpsertOutboxAsync<List<ResourceRequestPendingNotificationMessage>>(
270+
refId: $"auth_resource_request_accept_{request.Assignment.FromId}_{request.Assignment.ToId}",
271+
handler: "resource_request_pending",
272+
addValueFactory: msg =>
273+
{
274+
var schedule = DateTime.UtcNow.AddMinutes(15);
275+
msg.Schedule = schedule;
276+
msg.Timeout = TimeSpan.FromMinutes(1);
277+
278+
return [
279+
new ResourceRequestPendingNotificationMessage()
280+
{
281+
RecipientId = request.Assignment.FromId,
282+
RequesterId = request.Assignment.ToId,
283+
Resource = resourceId.ToString(),
284+
ExpectedDeliveredAt = schedule,
285+
}
286+
];
287+
},
288+
updateValueFactory: (msg, curr) =>
289+
{
290+
if (curr is null)
291+
{
292+
Activity.Current?.AddTag("RequestService.CreateRequestAssignmentResource.UpdateOutbox", "Current outbox message data is null? Creating new list");
293+
curr = [];
294+
}
295+
296+
var latestExisting = curr.Count > 0
297+
? curr.Max(b => b.ExpectedDeliveredAt)
298+
: DateTime.UtcNow.AddMinutes(15);
299+
300+
var candidate = DateTime.UtcNow.AddMinutes(15.0 / (curr.Count + 1));
301+
var schedule = candidate > latestExisting ? latestExisting : candidate;
302+
303+
curr.Add(new ResourceRequestPendingNotificationMessage()
304+
{
305+
RecipientId = request.Assignment.FromId,
306+
RequesterId = request.Assignment.ToId,
307+
Resource = resourceId.ToString(),
308+
ExpectedDeliveredAt = schedule,
309+
});
310+
311+
return curr;
312+
},
313+
cancellationToken: ct
314+
);
264315

265316
var res = await db.SaveChangesAsync(ct);
266317

src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.PersistenceEF/Contexts/AppDbContext.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
8080
public DbSet<RequestAssignmentPackage> RequestAssignmentPackages => Set<RequestAssignmentPackage>();
8181

8282
public DbSet<RequestAssignmentResource> RequestAssignmentResources => Set<RequestAssignmentResource>();
83-
83+
8484
public DbSet<ErrorQueue> ErrorQueue => Set<ErrorQueue>();
8585

8686
public DbSet<RightImportProgress> RightImportProgress => Set<RightImportProgress>();
@@ -347,7 +347,12 @@ public async Task UpsertOutboxAsync<T>(
347347

348348
var message = await OutboxMessages
349349
.AsTracking()
350-
.FirstOrDefaultAsync(o => o.RefId == refId, cancellationToken);
350+
.FirstOrDefaultAsync(
351+
o =>
352+
o.RefId == refId &&
353+
o.Handler == handler &&
354+
o.Status == OutboxStatus.Pending,
355+
cancellationToken);
351356

352357
UpsertOutbox(refId, handler, addValueFactory, updateValueFactory, message);
353358
}
@@ -400,7 +405,10 @@ public void UpsertOutbox<T>(
400405

401406
var message = OutboxMessages
402407
.AsTracking()
403-
.FirstOrDefault(o => o.RefId == refId);
408+
.FirstOrDefault(o =>
409+
o.RefId == refId &&
410+
o.Handler == handler &&
411+
o.Status == OutboxStatus.Pending);
404412

405413
UpsertOutbox(refId, handler, addValueFactory, updateValueFactory, message);
406414
}

0 commit comments

Comments
 (0)