using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Abp;
using Abp.Collections.Extensions;
using Abp.Configuration;
using Abp.Dependency;
using Abp.Domain.Uow;
using Abp.Runtime.Caching;
using Abp.Runtime.Session;
namespace IwbZero.Setting
{
///
/// This class implements to manage setting values in the database.
///
public class IwbSettingManager : IIwbSettingManager, ISingletonDependency
{
public const string ApplicationSettingsCacheKey = "ApplicationSettings";
///
/// Reference to the current Session.
///
public IAbpSession AbpSession { get; set; }
///
/// Reference to the setting store.
///
public ISettingStore SettingStore { get; set; }
private readonly IIwbSettingDefinitionManager _settingDefinitionManager;
private readonly ITypedCache> _applicationSettingCache;
private readonly ITypedCache> _tenantSettingCache;
private readonly ITypedCache> _userSettingCache;
///
public IwbSettingManager(IIwbSettingDefinitionManager settingDefinitionManager, ICacheManager cacheManager)
{
_settingDefinitionManager = settingDefinitionManager;
AbpSession = NullAbpSession.Instance;
SettingStore = IwbSettingStore.Instance;
_applicationSettingCache = cacheManager.GetApplicationSettingsCache();
_tenantSettingCache = cacheManager.GetTenantSettingsCache();
_userSettingCache = cacheManager.GetUserSettingsCache();
}
#region Public methods
public async Task RefreshAsync()
{
_settingDefinitionManager.Referesh();
await _applicationSettingCache.RemoveAsync(ApplicationSettingsCacheKey);
}
public Task RefreshForUserAsync(long userId)
{
return RefreshForUserAsync(new UserIdentifier(null, userId));
}
public async Task RefreshForUserAsync(UserIdentifier user)
{
_settingDefinitionManager.Referesh();
await _userSettingCache.RemoveAsync(user.ToUserIdentifierString());
}
///
public Task GetSettingValueAsync(string name)
{
return GetSettingValueInternalAsync(name, AbpSession.UserId);
}
public Task GetSettingValueForApplicationAsync(string name)
{
return GetSettingValueInternalAsync(name);
}
public Task GetSettingValueForApplicationAsync(string name, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, fallbackToDefault: fallbackToDefault);
}
public Task GetSettingValueForUserAsync(string name, long userId)
{
return GetSettingValueInternalAsync(name, userId);
}
public Task GetSettingValueForUserAsync(string name, long userId, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, userId, fallbackToDefault);
}
public async Task> GetAllSettingValuesAsync()
{
return await GetAllSettingValuesAsync(SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User);
}
///
public async Task> GetAllSettingValuesAsync(SettingScopes scopes)
{
var settingDefinitions = new Dictionary();
var settingValues = new Dictionary();
//Fill all setting with default values.
foreach (var setting in _settingDefinitionManager.GetAllSettingDefinitions())
{
settingDefinitions[setting.Name] = setting;
settingValues[setting.Name] = new SettingValueObject(setting.Name, setting.DefaultValue);
}
//Overwrite application settings
if (scopes.HasFlag(SettingScopes.Application))
{
foreach (var settingValue in await GetAllSettingValuesForApplicationAsync())
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Application))
{
continue;
}
if (!setting.IsInherited &&
((setting.Scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue) || (setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite tenant settings
if (scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForTenantAsync(AbpSession.TenantId.Value))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Tenant))
{
continue;
}
if (!setting.IsInherited &&
(setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite user settings
if (scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForUserAsync(AbpSession.ToUserIdentifier()))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
if (setting != null && setting.Scopes.HasFlag(SettingScopes.User))
{
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
}
return settingValues.Values.ToImmutableList();
}
///
public async Task> GetAllSettingValuesForApplicationAsync()
{
return (await GetApplicationSettingsAsync()).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
///
public async Task> GetAllSettingValuesForTenantAsync(int tenantId)
{
return (await GetReadOnlyTenantSettings(tenantId)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
public Task> GetAllSettingValuesForUserAsync(long userId)
{
return GetAllSettingValuesForUserAsync(new UserIdentifier(AbpSession.TenantId, userId));
}
public async Task> GetAllSettingValuesForUserAsync(UserIdentifier user)
{
return (await GetReadOnlyUserSettings(user)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
///
[UnitOfWork]
public virtual async Task ChangeSettingForApplicationAsync(string name, string value)
{
//await InsertOrUpdateOrDeleteSettingValueAsync(name, value, null);
_settingDefinitionManager.ChangeSettingDefinition(name, value);
await _applicationSettingCache.RemoveAsync(ApplicationSettingsCacheKey);
}
///
[UnitOfWork]
public virtual async Task ChangeSettingForTenantAsync(int tenantId, string name, string value)
{
//await InsertOrUpdateOrDeleteSettingValueAsync(name, value, null);
_settingDefinitionManager.ChangeSettingDefinition(name, value);
await _tenantSettingCache.RemoveAsync(tenantId);
}
[UnitOfWork]
public virtual Task ChangeSettingForUserAsync(long userId, string name, string value)
{
return ChangeSettingForUserAsync(new UserIdentifier(null, userId), name, value);
}
public async Task ChangeSettingForUserAsync(UserIdentifier user, string name, string value)
{
//await InsertOrUpdateOrDeleteSettingValueAsync(name, value, user.UserId);
_settingDefinitionManager.ChangeSettingDefinition(name, value);
await _userSettingCache.RemoveAsync(user.ToUserIdentifierString());
}
#endregion
#region Private methods
private async Task GetSettingValueInternalAsync(string name, long? userId = null, bool fallbackToDefault = true)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
//Get for user if defined
if (settingDefinition.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
{
var settingValue = await GetSettingValueForUserOrNullAsync(new UserIdentifier(null, userId.Value), name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
if (!settingDefinition.IsInherited)
{
return settingDefinition.DefaultValue;
}
}
////Get for tenant if defined
//if (settingDefinition.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
//{
// var settingValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
// if (settingValue != null)
// {
// return settingValue.Value;
// }
// if (!fallbackToDefault)
// {
// return null;
// }
// if (!settingDefinition.IsInherited)
// {
// return settingDefinition.DefaultValue;
// }
//}
//Get for application if defined
if (settingDefinition.Scopes.HasFlag(SettingScopes.Application))
{
var settingValue = await GetSettingValueForApplicationOrNullAsync(name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
}
//Not defined, get default value
return settingDefinition.DefaultValue;
}
private async Task InsertOrUpdateOrDeleteSettingValueAsync(string name, string value, long? userId)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
var settingValue = await SettingStore.GetSettingOrNullAsync(null, userId, name);
//Determine defaultValue;
var defaultValue = settingDefinition.DefaultValue;
if (settingDefinition.IsInherited)
{
//For Tenant and User, Application's value overrides Setting Definition's default value.
if (userId.HasValue)
{
var applicationValue = await GetSettingValueForApplicationOrNullAsync(name);
if (applicationValue != null)
{
defaultValue = applicationValue.Value;
}
}
//For User, Tenants's value overrides Application's default value.
//if (userId.HasValue )
//{
// var tenantValue = await GetSettingValueForTenantOrNullAsync( name);
// if (tenantValue != null)
// {
// defaultValue = tenantValue.Value;
// }
//}
}
//No need to store on database if the value is the default value
if (value == defaultValue)
{
if (settingValue != null)
{
await SettingStore.DeleteAsync(settingValue);
}
return null;
}
//If it's not default value and not stored on database, then insert it
if (settingValue == null)
{
settingValue = new SettingInfo
{
//TenantId = tenantId,
UserId = userId,
Name = name,
Value = value
};
await SettingStore.CreateAsync(settingValue);
return settingValue;
}
//It's same value in database, no need to update
if (settingValue.Value == value)
{
return settingValue;
}
//Update the setting on database.
settingValue.Value = value;
await SettingStore.UpdateAsync(settingValue);
return settingValue;
}
private async Task GetSettingValueForApplicationOrNullAsync(string name)
{
return (await GetApplicationSettingsAsync()).GetOrDefault(name);
}
private async Task GetSettingValueForUserOrNullAsync(UserIdentifier user, string name)
{
return (await GetReadOnlyUserSettings(user)).GetOrDefault(name);
}
private async Task> GetApplicationSettingsAsync()
{
return await _applicationSettingCache.GetAsync(ApplicationSettingsCacheKey, async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(null, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task> GetReadOnlyTenantSettings(int tenantId)
{
var cachedDictionary = await GetTenantSettingsFromCache(tenantId);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task> GetReadOnlyUserSettings(UserIdentifier user)
{
var cachedDictionary = await GetUserSettingsFromCache(user);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task> GetTenantSettingsFromCache(int tenantId)
{
return await _tenantSettingCache.GetAsync(
tenantId,
async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(tenantId, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task> GetUserSettingsFromCache(UserIdentifier user)
{
return await _userSettingCache.GetAsync(
user.ToUserIdentifierString(),
async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(user.TenantId, user.UserId);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
public Task GetSettingValueForUserAsync(string name, UserIdentifier user)
{
Check.NotNull(name, nameof(name));
Check.NotNull(user, nameof(user));
return GetSettingValueForUserAsync(name, user.UserId);
}
#endregion
#region Nested classes
private class SettingValueObject : ISettingValue
{
public string Name { get; private set; }
public string Value { get; private set; }
public SettingValueObject(string name, string value)
{
Value = value;
Name = name;
}
}
#endregion
}
}