VzTenantManager.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. using System.Globalization;
  2. using System.Text.RegularExpressions;
  3. using Abp;
  4. using Abp.Domain.Repositories;
  5. using Abp.Domain.Services;
  6. using Abp.Domain.Uow;
  7. using Abp.Localization;
  8. using Abp.Runtime.Caching;
  9. using Abp.UI;
  10. using VberZero;
  11. using VberZero.BaseSystem.MultiTenancy;
  12. // ReSharper disable once CheckNamespace - This is done to add extension methods to Microsoft.Extensions.DependencyInjection namespace
  13. namespace Microsoft.Extensions.DependencyInjection;
  14. /// <summary>
  15. /// 租户管理器为 <see cref="Tenant"/> 实现域逻辑
  16. /// </summary>
  17. public class VzTenantManager : IDomainService
  18. //, IEventHandler<EntityChangedEventData<AbpTenant>>
  19. //,IEventHandler<EntityDeletedEventData<Edition>>
  20. {
  21. //public AbpEditionManager EditionManager { get; set; }
  22. public ILocalizationManager LocalizationManager { get; set; }
  23. protected string LocalizationSourceName { get; set; }
  24. public ICacheManager CacheManager { get; set; }
  25. //public IFeatureManager FeatureManager { get; set; }
  26. public IUnitOfWorkManager UnitOfWorkManager { get; set; }
  27. protected IRepository<Tenant> TenantRepository { get; set; }
  28. //protected IRepository<TenantFeatureSetting, long> TenantFeatureRepository { get; set; }
  29. //private readonly IAbpZeroFeatureValueStore _featureValueStore;
  30. public VzTenantManager(IRepository<Tenant> tenantRepository)
  31. {
  32. //_featureValueStore = featureValueStore;
  33. TenantRepository = tenantRepository;
  34. //TenantFeatureRepository = tenantFeatureRepository;
  35. //EditionManager = editionManager;
  36. LocalizationManager = NullLocalizationManager.Instance;
  37. LocalizationSourceName = VzConsts.LocalizationSourceName;
  38. }
  39. public virtual IQueryable<Tenant> Tenants => TenantRepository.GetAll();
  40. public virtual async Task CreateAsync(Tenant tenant)
  41. {
  42. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  43. {
  44. await ValidateTenantAsync(tenant);
  45. if (await TenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenant.TenancyName) != null)
  46. {
  47. throw new UserFriendlyException(string.Format(L("TenancyNameIsAlreadyTaken"), tenant.TenancyName));
  48. }
  49. await TenantRepository.InsertAsync(tenant);
  50. });
  51. }
  52. public virtual void Create(Tenant tenant)
  53. {
  54. UnitOfWorkManager.WithUnitOfWork(() =>
  55. {
  56. ValidateTenant(tenant);
  57. if (TenantRepository.FirstOrDefault(t => t.TenancyName == tenant.TenancyName) != null)
  58. {
  59. throw new UserFriendlyException(string.Format(L("TenancyNameIsAlreadyTaken"), tenant.TenancyName));
  60. }
  61. TenantRepository.Insert(tenant);
  62. });
  63. }
  64. public virtual async Task UpdateAsync(Tenant tenant)
  65. {
  66. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  67. {
  68. if (await TenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenant.TenancyName && t.Id != tenant.Id) != null)
  69. {
  70. throw new UserFriendlyException(string.Format(L("TenancyNameIsAlreadyTaken"), tenant.TenancyName));
  71. }
  72. await TenantRepository.UpdateAsync(tenant);
  73. });
  74. }
  75. public virtual void Update(Tenant tenant)
  76. {
  77. UnitOfWorkManager.WithUnitOfWork(() =>
  78. {
  79. if (TenantRepository.FirstOrDefault(t => t.TenancyName == tenant.TenancyName && t.Id != tenant.Id) != null)
  80. {
  81. throw new UserFriendlyException(string.Format(L("TenancyNameIsAlreadyTaken"), tenant.TenancyName));
  82. }
  83. TenantRepository.Update(tenant);
  84. });
  85. }
  86. public virtual async Task<Tenant> FindByIdAsync(int id)
  87. {
  88. return await UnitOfWorkManager.WithUnitOfWorkAsync(async () => await TenantRepository.FirstOrDefaultAsync(id));
  89. }
  90. public virtual Tenant FindById(int id)
  91. {
  92. return UnitOfWorkManager.WithUnitOfWork(() => TenantRepository.FirstOrDefault(id));
  93. }
  94. public virtual async Task<Tenant> GetByIdAsync(int id)
  95. {
  96. var tenant = await FindByIdAsync(id);
  97. if (tenant == null)
  98. {
  99. throw new AbpException("There is no tenant with id: " + id);
  100. }
  101. return tenant;
  102. }
  103. public virtual Tenant GetById(int id)
  104. {
  105. var tenant = FindById(id);
  106. if (tenant == null)
  107. {
  108. throw new AbpException("There is no tenant with id: " + id);
  109. }
  110. return tenant;
  111. }
  112. public virtual async Task<Tenant> FindByTenancyNameAsync(string tenancyName)
  113. {
  114. return await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  115. {
  116. return await TenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenancyName);
  117. });
  118. }
  119. public virtual Tenant FindByTenancyName(string tenancyName)
  120. {
  121. return UnitOfWorkManager.WithUnitOfWork(() =>
  122. {
  123. return TenantRepository.FirstOrDefault(t => t.TenancyName == tenancyName);
  124. });
  125. }
  126. public virtual async Task DeleteAsync(Tenant tenant)
  127. {
  128. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  129. {
  130. await TenantRepository.DeleteAsync(tenant);
  131. });
  132. }
  133. public virtual void Delete(Tenant tenant)
  134. {
  135. UnitOfWorkManager.WithUnitOfWork(() =>
  136. {
  137. TenantRepository.Delete(tenant);
  138. });
  139. }
  140. protected virtual async Task ValidateTenantAsync(Tenant tenant)
  141. {
  142. await ValidateTenancyNameAsync(tenant.TenancyName);
  143. }
  144. protected virtual void ValidateTenant(Tenant tenant)
  145. {
  146. ValidateTenancyName(tenant.TenancyName);
  147. }
  148. protected virtual Task ValidateTenancyNameAsync(string tenancyName)
  149. {
  150. if (!Regex.IsMatch(tenancyName, Tenant.TenancyNameRegex))
  151. {
  152. throw new UserFriendlyException(L("InvalidTenancyName"));
  153. }
  154. return Task.FromResult(0);
  155. }
  156. protected virtual void ValidateTenancyName(string tenancyName)
  157. {
  158. if (!Regex.IsMatch(tenancyName, Tenant.TenancyNameRegex))
  159. {
  160. throw new UserFriendlyException(L("InvalidTenancyName"));
  161. }
  162. }
  163. protected virtual string L(string name)
  164. {
  165. return LocalizationManager.GetString(LocalizationSourceName, name);
  166. }
  167. protected virtual string L(string name, CultureInfo cultureInfo)
  168. {
  169. return LocalizationManager.GetString(LocalizationSourceName, name, cultureInfo);
  170. }
  171. /*
  172. public Task<string> GetFeatureValueOrNullAsync(int tenantId, string featureName)
  173. {
  174. return _featureValueStore.GetValueOrNullAsync(tenantId, featureName);
  175. }
  176. public string GetFeatureValueOrNull(int tenantId, string featureName)
  177. {
  178. return _featureValueStore.GetValueOrNull(tenantId, featureName);
  179. }
  180. public virtual async Task<IReadOnlyList<NameValue>> GetFeatureValuesAsync(int tenantId)
  181. {
  182. var values = new List<NameValue>();
  183. foreach (var feature in FeatureManager.GetAll())
  184. {
  185. values.Add(new NameValue(feature.Name, await GetFeatureValueOrNullAsync(tenantId, feature.Name) ?? feature.DefaultValue));
  186. }
  187. return values;
  188. }
  189. public virtual IReadOnlyList<NameValue> GetFeatureValues(int tenantId)
  190. {
  191. var values = new List<NameValue>();
  192. foreach (var feature in FeatureManager.GetAll())
  193. {
  194. values.Add(new NameValue(feature.Name, GetFeatureValueOrNull(tenantId, feature.Name) ?? feature.DefaultValue));
  195. }
  196. return values;
  197. }
  198. public virtual async Task SetFeatureValuesAsync(int tenantId, params NameValue[] values)
  199. {
  200. if (values.IsNullOrEmpty())
  201. {
  202. return;
  203. }
  204. foreach (var value in values)
  205. {
  206. await SetFeatureValueAsync(tenantId, value.Name, value.Value);
  207. }
  208. }
  209. public virtual void SetFeatureValues(int tenantId, params NameValue[] values)
  210. {
  211. if (values.IsNullOrEmpty())
  212. {
  213. return;
  214. }
  215. foreach (var value in values)
  216. {
  217. SetFeatureValue(tenantId, value.Name, value.Value);
  218. }
  219. }
  220. public virtual async Task SetFeatureValueAsync(int tenantId, string featureName, string value)
  221. {
  222. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  223. {
  224. await SetFeatureValueAsync(await GetByIdAsync(tenantId), featureName, value);
  225. });
  226. }
  227. public virtual void SetFeatureValue(int tenantId, string featureName, string value)
  228. {
  229. UnitOfWorkManager.WithUnitOfWork(() =>
  230. {
  231. SetFeatureValue(GetById(tenantId), featureName, value);
  232. });
  233. }
  234. public virtual async Task SetFeatureValueAsync(AbpTenant tenant, string featureName, string value)
  235. {
  236. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  237. {
  238. //No need to change if it's already equals to the current value
  239. if (await GetFeatureValueOrNullAsync(tenant.Id, featureName) == value)
  240. {
  241. return;
  242. }
  243. //Get the current feature setting
  244. TenantFeatureSetting currentSetting;
  245. using (UnitOfWorkManager.Current.EnableFilter(AbpDataFilters.MayHaveTenant))
  246. using (UnitOfWorkManager.Current.SetTenantId(tenant.Id))
  247. {
  248. currentSetting = await TenantFeatureRepository.FirstOrDefaultAsync(f => f.Name == featureName);
  249. }
  250. //Get the feature
  251. var feature = FeatureManager.GetOrNull(featureName);
  252. if (feature == null)
  253. {
  254. if (currentSetting != null)
  255. {
  256. await TenantFeatureRepository.DeleteAsync(currentSetting);
  257. }
  258. return;
  259. }
  260. //Determine default value
  261. var defaultValue = tenant.EditionId.HasValue
  262. ? (await EditionManager.GetFeatureValueOrNullAsync(tenant.EditionId.Value, featureName) ?? feature.DefaultValue)
  263. : feature.DefaultValue;
  264. //No need to store value if it's default
  265. if (value == defaultValue)
  266. {
  267. if (currentSetting != null)
  268. {
  269. await TenantFeatureRepository.DeleteAsync(currentSetting);
  270. }
  271. return;
  272. }
  273. //Insert/update the feature value
  274. if (currentSetting == null)
  275. {
  276. await TenantFeatureRepository.InsertAsync(new TenantFeatureSetting(tenant.Id, featureName, value));
  277. }
  278. else
  279. {
  280. currentSetting.Value = value;
  281. }
  282. });
  283. }
  284. public virtual void SetFeatureValue(AbpTenant tenant, string featureName, string value)
  285. {
  286. UnitOfWorkManager.WithUnitOfWork(() =>
  287. {
  288. //No need to change if it's already equals to the current value
  289. if (GetFeatureValueOrNull(tenant.Id, featureName) == value)
  290. {
  291. return;
  292. }
  293. //Get the current feature setting
  294. TenantFeatureSetting currentSetting;
  295. using (UnitOfWorkManager.Current.EnableFilter(AbpDataFilters.MayHaveTenant))
  296. using (UnitOfWorkManager.Current.SetTenantId(tenant.Id))
  297. {
  298. currentSetting = TenantFeatureRepository.FirstOrDefault(f => f.Name == featureName);
  299. }
  300. //Get the feature
  301. var feature = FeatureManager.GetOrNull(featureName);
  302. if (feature == null)
  303. {
  304. if (currentSetting != null)
  305. {
  306. TenantFeatureRepository.Delete(currentSetting);
  307. }
  308. return;
  309. }
  310. //Determine default value
  311. var defaultValue = tenant.EditionId.HasValue
  312. ? (EditionManager.GetFeatureValueOrNull(tenant.EditionId.Value, featureName) ?? feature.DefaultValue)
  313. : feature.DefaultValue;
  314. //No need to store value if it's default
  315. if (value == defaultValue)
  316. {
  317. if (currentSetting != null)
  318. {
  319. TenantFeatureRepository.Delete(currentSetting);
  320. }
  321. return;
  322. }
  323. //Insert/update the feature value
  324. if (currentSetting == null)
  325. {
  326. TenantFeatureRepository.Insert(new TenantFeatureSetting(tenant.Id, featureName, value));
  327. }
  328. else
  329. {
  330. currentSetting.Value = value;
  331. }
  332. });
  333. }
  334. /// <summary>
  335. /// Resets all custom feature settings for a tenant.
  336. /// Tenant will have features according to it's edition.
  337. /// </summary>
  338. /// <param name="tenantId">Tenant Id</param>
  339. public virtual async Task ResetAllFeaturesAsync(int tenantId)
  340. {
  341. await UnitOfWorkManager.WithUnitOfWorkAsync(async () =>
  342. {
  343. using (UnitOfWorkManager.Current.EnableFilter(AbpDataFilters.MayHaveTenant))
  344. using (UnitOfWorkManager.Current.SetTenantId(tenantId))
  345. {
  346. await TenantFeatureRepository.DeleteAsync(f => f.TenantId == tenantId);
  347. }
  348. });
  349. }
  350. /// <summary>
  351. /// Resets all custom feature settings for a tenant.
  352. /// Tenant will have features according to it's edition.
  353. /// </summary>
  354. /// <param name="tenantId">Tenant Id</param>
  355. public virtual void ResetAllFeatures(int tenantId)
  356. {
  357. UnitOfWorkManager.WithUnitOfWork(() =>
  358. {
  359. using (UnitOfWorkManager.Current.EnableFilter(AbpDataFilters.MayHaveTenant))
  360. using (UnitOfWorkManager.Current.SetTenantId(tenantId))
  361. {
  362. TenantFeatureRepository.Delete(f => f.TenantId == tenantId);
  363. }
  364. });
  365. }*/
  366. /*
  367. public void HandleEvent(EntityChangedEventData<AbpTenant> eventData)
  368. {
  369. if (eventData.Entity.IsTransient())
  370. {
  371. return;
  372. }
  373. CacheManager.GeAbpTenantFeatureCache().Remove(eventData.Entity.Id);
  374. }
  375. public virtual void HandleEvent(EntityDeletedEventData<Edition> eventData)
  376. {
  377. UnitOfWorkManager.WithUnitOfWork(() =>
  378. {
  379. var relatedTenants = TenantRepository.GetAllList(t => t.EditionId == eventData.Entity.Id);
  380. foreach (var relatedTenant in relatedTenants)
  381. {
  382. relatedTenant.EditionId = null;
  383. }
  384. });
  385. }
  386. */
  387. }