Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Http;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
Expand All @@ -18,6 +19,7 @@ Task<HttpResponseMessage> HttpAsync(
string? authToken = null,
(string username, string password)? basicAuth = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
IReadOnlyDictionary<string, string>? extraHeaders = null,
CancellationToken cancellationToken = default);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Polly;
using Polly.Retry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand Down Expand Up @@ -114,10 +115,11 @@ public async Task<HttpResponseMessage> HttpAsync(
string? authToken = null,
(string username, string password)? basicAuth = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
IReadOnlyDictionary<string, string>? extraHeaders = null,
CancellationToken cancellationToken = default)
{
return await SendWithClientAsync(
_httpClient, httpVerb, resource, body, authToken, basicAuth, completionOption, cancellationToken);
_httpClient, httpVerb, resource, body, authToken, basicAuth, completionOption, extraHeaders, cancellationToken);
}


Expand All @@ -138,7 +140,7 @@ public Task<HttpResponseMessage> HttpAsyncSecured(
EnsureMutualTlsClient(certPath, certPassword);

return SendWithClientAsync(
_mtlsClient!, httpVerb, resource, body, authToken, basicAuth, HttpCompletionOption.ResponseContentRead, cancellationToken);
_mtlsClient!, httpVerb, resource, body, authToken, basicAuth, HttpCompletionOption.ResponseContentRead, null, cancellationToken);
}


Expand Down Expand Up @@ -193,6 +195,7 @@ private async Task<HttpResponseMessage> SendWithClientAsync(
string? authToken,
(string username, string password)? basicAuth,
HttpCompletionOption completionOption,
IReadOnlyDictionary<string, string>? extraHeaders,
CancellationToken cancellationToken)
{
// Build final URL
Expand All @@ -208,7 +211,7 @@ private async Task<HttpResponseMessage> SendWithClientAsync(
return await _pipeline.ExecuteAsync(async ct =>
{
using var requestMessage =
BuildRequestMessage(httpVerb, fullUrl, body, authToken, basicAuth);
BuildRequestMessage(httpVerb, fullUrl, body, authToken, basicAuth, extraHeaders);

return await client.SendAsync(requestMessage, completionOption, ct)
.ConfigureAwait(false);
Expand All @@ -226,7 +229,8 @@ private static HttpRequestMessage BuildRequestMessage(
Uri fullUrl,
object? body,
string? authToken,
(string username, string password)? basicAuth)
(string username, string password)? basicAuth,
IReadOnlyDictionary<string, string>? extraHeaders = null)
{
var requestMessage = new HttpRequestMessage(httpVerb, fullUrl);
requestMessage.Headers.Accept.Clear();
Expand All @@ -248,6 +252,16 @@ private static HttpRequestMessage BuildRequestMessage(
requestMessage.Headers.Add(AuthorizationHeader, $"Basic {encoded}");
}

// Additional headers (e.g. API keys) not covered by the auth-token/basic-auth cases above
if (extraHeaders != null)
{
foreach (var header in extraHeaders)
{
requestMessage.Headers.Remove(header.Key);
requestMessage.Headers.Add(header.Key, header.Value);
}
}

// Body
if (body != null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Threading.Tasks;

namespace Unity.Modules.Shared.PostTenantCreation;

/// <summary>
/// A single step in the post-tenant-creation sequence, run as part of
/// <c>PostTenantCreationSequenceJob</c> after a new tenant is created. Implement this in any
/// module and register it as an <see cref="Volo.Abp.DependencyInjection.ITransientDependency"/> to
/// have it picked up automatically - no changes to the sequencing job are needed.
/// </summary>
public interface IPostTenantCreationStep
{
/// <summary>Determines execution order relative to other steps (ascending).</summary>
int Order { get; }

/// <summary>Short, human-readable name used in logging.</summary>
string StepName { get; }

/// <summary>
/// When true, a failure in this step is logged and the sequence continues to the next step.
/// When false, a failure stops the sequence - later steps do not run.
/// </summary>
bool ContinueOnError { get; }

/// <summary>
/// Validated before <see cref="ExecuteAsync"/> runs. When false, the step is skipped (logged,
/// not treated as a failure) and the sequence moves on to the next step. Defaults to true -
/// override to check preconditions such as required configuration being present.
/// </summary>
Task<bool> CanExecuteAsync(Guid tenantId) => Task.FromResult(true);

Task ExecuteAsync(Guid tenantId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IOnboardingRequestAppService : IApplicationService
{
Task<PagedResultDto<OnboardingRequestDto>> GetListAsync(OnboardingListRequestDto input);
Task<OnboardingRequestDto?> GetAsync(Guid id);
Task<OnboardingValidationResultDto> ValidateAsync(Guid id, string? tenantNameFieldKey, string? superUsersFieldKey, string? branchFieldKey = null, string? featuresFieldKey = null, string? ministryFieldKey = null, string? programAreaFieldKey = null);
Task<OnboardingValidationResultDto> ValidateAsync(Guid id, string? tenantNameFieldKey, string? superUsersFieldKey, string? branchFieldKey = null, string? featuresFieldKey = null, string? ministryFieldKey = null, string? programAreaFieldKey = null, string? displayNameFieldKey = null, string? divisionFieldKey = null);
Task CreateTenantAsync(Guid id, CreateTenantInputDto? input);
Task<OnboardingColumnSchemaDto> GetColumnSchemaAsync(string? category = null);
Task<List<string>> GetAvailableCategoriesAsync();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Unity.TenantManagement.Metabase;

public static class MetabaseSettings
{
/// <summary>
/// Comma-separated list of user emails to add to a tenant's Metabase group.
/// Stored Global (the running default applied to new tenants) and per-tenant, "T" provider
/// (the resolved snapshot captured when that tenant was created).
/// </summary>
public const string UserEmails = "Metabase.UserEmails";
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,32 @@ public class OnboardingColumnSchemaDto
{
public List<OnboardingColumnDto> Columns { get; set; } = [];
public string? TenantNameFieldKey { get; set; }
public string? DisplayNameFieldKey { get; set; }
public string? SuperUsersFieldKey { get; set; }
public string? BranchFieldKey { get; set; }
public string? FeaturesFieldKey { get; set; }
public string? MinistryFieldKey { get; set; }
public string? DivisionFieldKey { get; set; }
public string? ProgramAreaFieldKey { get; set; }
}

public class CreateTenantInputDto
{
public string? TenantNameFieldKey { get; set; }
public string? DisplayNameFieldKey { get; set; }
public string? SuperUsersFieldKey { get; set; }
public string? BranchFieldKey { get; set; }
public string? FeaturesFieldKey { get; set; }
public string? MinistryFieldKey { get; set; }
public string? DivisionFieldKey { get; set; }
public string? ProgramAreaFieldKey { get; set; }

/// <summary>Comma-separated emails checked in the Metabase tab - sent to TenantCreateDto as-is.</summary>
public string? MetabaseUserEmails { get; set; }

/// <summary>Comma-separated subset of newly-added Metabase emails to persist as the new Global default.</summary>
public string? MetabaseNewDefaultUserEmails { get; set; }

/// <summary>Comma-separated default Metabase emails explicitly removed - deleted from the Global default.</summary>
public string? MetabaseRemovedDefaultUserEmails { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class OnboardingRequestDto
public Guid Id { get; set; }
public string SubmissionNumber { get; set; } = string.Empty;
public string TenantName { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string TenantDescription { get; set; } = string.Empty;
public string ProgramAreaName { get; set; } = string.Empty;
public string ProgramAreaDescription { get; set; } = string.Empty;
Expand All @@ -18,6 +19,7 @@ public class OnboardingRequestDto
public string ExecutiveDirector { get; set; } = string.Empty;
public string Branch { get; set; } = string.Empty;
public string Ministry { get; set; } = string.Empty;
public string Division { get; set; } = string.Empty;
public string Status { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
public DateTime? SubmissionDate { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ public class TenantCreateDto : TenantCreateOrUpdateDtoBase
public string UserIdentifier { get; set; } = string.Empty;
/// <summary>Comma-separated ABP feature keys to enable on the new tenant (e.g. "Unity.Payments,Unity.Reporting").</summary>
public string? FeatureKeys { get; set; }
/// <summary>Comma-separated user emails to add to this tenant's Metabase group.</summary>
public string? MetabaseUserEmails { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public abstract class TenantCreateOrUpdateDtoBase : ExtensibleObject
[Display(Name = "TenantName")]
public string Name { get; set; }

public string DisplayName { get; set; } = string.Empty;
public string Division { get; set; } = string.Empty;
public string Branch { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Unity.TenantManagement;
public class TenantDto : ExtensibleEntityDto<Guid>, IHasConcurrencyStamp
{
public string Name { get; set; }
public string DisplayName { get; set; } = string.Empty;
public string Division { get; set; } = string.Empty;
public string Branch { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Volo.Abp.Settings;
using Volo.Abp.SettingManagement;

namespace Unity.TenantManagement.Metabase;

public class MetabaseSettingDefinitionProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
context.Add(
new SettingDefinition(
MetabaseSettings.UserEmails,
defaultValue: null,
isVisibleToClients: false,
isInherited: false,
isEncrypted: false)
.WithProviders(GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ public override void Define(ISettingDefinitionContext context)
{
context.Add(
OnboardingDef(OnboardingColumnConfigSettings.TenantNameFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.DisplayNameFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.SuperUsersFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.BranchFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.FeaturesFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.MinistryFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.DivisionFieldKey),
OnboardingDef(OnboardingColumnConfigSettings.ProgramAreaFieldKey)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ namespace Unity.TenantManagement.Onboarding;
public static class OnboardingColumnConfigSettings
{
public const string TenantNameFieldKey = "Onboarding.ColumnConfig.TenantNameFieldKey";
public const string DisplayNameFieldKey = "Onboarding.ColumnConfig.DisplayNameFieldKey";
public const string SuperUsersFieldKey = "Onboarding.ColumnConfig.SuperUsersFieldKey";
public const string BranchFieldKey = "Onboarding.ColumnConfig.BranchFieldKey";
public const string FeaturesFieldKey = "Onboarding.ColumnConfig.FeaturesFieldKey";
public const string MinistryFieldKey = "Onboarding.ColumnConfig.MinistryFieldKey";
public const string DivisionFieldKey = "Onboarding.ColumnConfig.DivisionFieldKey";
public const string ProgramAreaFieldKey = "Onboarding.ColumnConfig.ProgramAreaFieldKey";
}
Loading
Loading