diff --git a/common/ASC.Api.Core/Model/TaskProgressDto.cs b/common/ASC.Api.Core/Model/TaskProgressDto.cs new file mode 100644 index 0000000000..6985c942f6 --- /dev/null +++ b/common/ASC.Api.Core/Model/TaskProgressDto.cs @@ -0,0 +1,43 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Api.Core.Model; +public class TaskProgressDto +{ + public bool IsCompleted { get; set; } + public int Progress { get; set; } + + public static TaskProgressDto GetSample() + { + return new TaskProgressDto + { + IsCompleted = true, + Progress = 0 + }; + } +} + + diff --git a/common/ASC.Core.Common/Data/DbQuotaService.cs b/common/ASC.Core.Common/Data/DbQuotaService.cs index 13f410fed1..f52d347c75 100644 --- a/common/ASC.Core.Common/Data/DbQuotaService.cs +++ b/common/ASC.Core.Common/Data/DbQuotaService.cs @@ -101,12 +101,8 @@ class DbQuotaService : IQuotaService using var coreDbContext = _dbContextFactory.CreateDbContext(); using var tx = coreDbContext.Database.BeginTransaction(); - AddQuota(coreDbContext, Guid.Empty); - if (row.UserId != Guid.Empty) - { - AddQuota(coreDbContext, row.UserId); - } + AddQuota(coreDbContext, row.UserId); tx.Commit(); }); diff --git a/common/ASC.Data.Storage/TenantQuotaController.cs b/common/ASC.Data.Storage/TenantQuotaController.cs index ac47292bbc..7d7531170f 100644 --- a/common/ASC.Data.Storage/TenantQuotaController.cs +++ b/common/ASC.Data.Storage/TenantQuotaController.cs @@ -76,6 +76,7 @@ public class TenantQuotaController : IQuotaController CurrentSize += size; } + SetTenantQuotaRow(module, domain, size, dataTag, true, Guid.Empty); SetTenantQuotaRow(module, domain, size, dataTag, true, _authContext.CurrentAccount.ID); } @@ -87,6 +88,7 @@ public class TenantQuotaController : IQuotaController CurrentSize += size; } + SetTenantQuotaRow(module, domain, size, dataTag, true, Guid.Empty); SetTenantQuotaRow(module, domain, size, dataTag, true, _authContext.CurrentAccount.ID); } diff --git a/products/ASC.Files/Core/Configuration/FilesSpaceUsageStatManager.cs b/products/ASC.Files/Core/Configuration/FilesSpaceUsageStatManager.cs index a095d40b12..83805fb34c 100644 --- a/products/ASC.Files/Core/Configuration/FilesSpaceUsageStatManager.cs +++ b/products/ASC.Files/Core/Configuration/FilesSpaceUsageStatManager.cs @@ -27,7 +27,7 @@ namespace ASC.Web.Files; [Scope] -public class FilesSpaceUsageStatManager : SpaceUsageStatManager +public class FilesSpaceUsageStatManager : SpaceUsageStatManager, IUserSpaceUsage { private readonly IDbContextFactory _dbContextFactory; private readonly TenantManager _tenantManager; @@ -37,6 +37,9 @@ public class FilesSpaceUsageStatManager : SpaceUsageStatManager private readonly CommonLinkUtility _commonLinkUtility; private readonly GlobalFolderHelper _globalFolderHelper; private readonly PathProvider _pathProvider; + private readonly IDaoFactory _daoFactory; + private readonly GlobalFolder _globalFolder; + private readonly FileMarker _fileMarker; public FilesSpaceUsageStatManager( IDbContextFactory dbContextFactory, @@ -46,7 +49,10 @@ public class FilesSpaceUsageStatManager : SpaceUsageStatManager DisplayUserSettingsHelper displayUserSettingsHelper, CommonLinkUtility commonLinkUtility, GlobalFolderHelper globalFolderHelper, - PathProvider pathProvider) + PathProvider pathProvider, + IDaoFactory daoFactory, + GlobalFolder globalFolder, + FileMarker fileMarker) { _dbContextFactory = dbContextFactory; _tenantManager = tenantManager; @@ -56,6 +62,9 @@ public class FilesSpaceUsageStatManager : SpaceUsageStatManager _commonLinkUtility = commonLinkUtility; _globalFolderHelper = globalFolderHelper; _pathProvider = pathProvider; + _daoFactory = daoFactory; + _globalFolder = globalFolder; + _fileMarker = fileMarker; } public override ValueTask> GetStatDataAsync() @@ -107,31 +116,8 @@ public class FilesSpaceUsageStatManager : SpaceUsageStatManager .ToListAsync(); } -} -[Scope] -public class FilesUserSpaceUsage : IUserSpaceUsage -{ - private readonly IDbContextFactory _dbContextFactory; - private readonly TenantManager _tenantManager; - private readonly GlobalFolder _globalFolder; - private readonly FileMarker _fileMarker; - private readonly IDaoFactory _daoFactory; - public FilesUserSpaceUsage( - IDbContextFactory dbContextFactory, - TenantManager tenantManager, - GlobalFolder globalFolder, - FileMarker fileMarker, - IDaoFactory daoFactory) - { - _dbContextFactory = dbContextFactory; - _tenantManager = tenantManager; - _globalFolder = globalFolder; - _fileMarker = fileMarker; - _daoFactory = daoFactory; - } - public async Task GetUserSpaceUsageAsync(Guid userId) { var tenantId = _tenantManager.GetCurrentTenant().Id; @@ -143,4 +129,15 @@ public class FilesUserSpaceUsage : IUserSpaceUsage .Where(r => r.TenantId == tenantId && r.CreateBy == userId && (r.ParentId == my || r.ParentId == trash)) .SumAsync(r => r.ContentLength); } + + public async Task RecalculateUserQuota(int TenantId, Guid userId) + { + _tenantManager.SetCurrentTenant(TenantId); + var size = await GetUserSpaceUsageAsync(userId); + + _tenantManager.SetTenantQuotaRow( + new TenantQuotaRow { Tenant = TenantId, Path = $"/{FileConstant.ModuleId}/", Counter = size, Tag = WebItemManager.DocumentsProductID.ToString(), UserId = userId, LastModified = DateTime.UtcNow }, + false); + } + } diff --git a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs index fbfe876687..0d30053e3d 100644 --- a/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs +++ b/products/ASC.Files/Core/Configuration/ProductEntryPoint.cs @@ -31,7 +31,7 @@ public class ProductEntryPoint : Product { internal const string ProductPath = "/products/files/"; - //public FilesSpaceUsageStatManager FilesSpaceUsageStatManager { get; } + private readonly FilesSpaceUsageStatManager _filesSpaceUsageStatManager; private readonly CoreBaseSettings _coreBaseSettings; private readonly AuthContext _authContext; private readonly UserManager _userManager; @@ -42,7 +42,7 @@ public class ProductEntryPoint : Product public ProductEntryPoint() { } public ProductEntryPoint( - // FilesSpaceUsageStatManager filesSpaceUsageStatManager, + FilesSpaceUsageStatManager filesSpaceUsageStatManager, CoreBaseSettings coreBaseSettings, AuthContext authContext, UserManager userManager, @@ -50,7 +50,7 @@ public class ProductEntryPoint : Product // SubscriptionManager subscriptionManager ) { - // FilesSpaceUsageStatManager = filesSpaceUsageStatManager; + _filesSpaceUsageStatManager = filesSpaceUsageStatManager; _coreBaseSettings = coreBaseSettings; _authContext = authContext; _userManager = userManager; @@ -83,7 +83,7 @@ public class ProductEntryPoint : Product LargeIconFileName = "images/files.svg", DefaultSortOrder = 10, //SubscriptionManager = SubscriptionManager, - //SpaceUsageStatManager = FilesSpaceUsageStatManager, + SpaceUsageStatManager = _filesSpaceUsageStatManager, AdminOpportunities = adminOpportunities, UserOpportunities = userOpportunities, CanNotBeDisabled = true, diff --git a/products/ASC.Files/Core/Core/UsersQuotaSyncOperation.cs b/products/ASC.Files/Core/Core/UsersQuotaSyncOperation.cs new file mode 100644 index 0000000000..55c334b9df --- /dev/null +++ b/products/ASC.Files/Core/Core/UsersQuotaSyncOperation.cs @@ -0,0 +1,185 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Web.Files; + +[Singletone(Additional = typeof(UsersQuotaOperationExtension))] +public class UsersQuotaSyncOperation +{ + public const string CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME = "userQuotaOperation"; + + private readonly DistributedTaskQueue _progressQueue; + + private readonly IServiceProvider _serviceProvider; + + + public void RecalculateQuota(Tenant tenant) + { + var item = _progressQueue.GetAllTasks().FirstOrDefault(t => t.TenantId == tenant.Id); + if (item != null && item.IsCompleted) + { + _progressQueue.DequeueTask(item.Id); + item = null; + } + + if (item == null) + { + item = _serviceProvider.GetRequiredService(); + item.InitJob(tenant); + _progressQueue.EnqueueTask(item.RunJobAsync, item); + } + } + public TaskProgressDto CheckRecalculateQuota(Tenant tenant) + { + var item = _progressQueue.GetAllTasks().FirstOrDefault(t => t.TenantId == tenant.Id); + var progress = new TaskProgressDto(); + + if (item == null) + { + progress.IsCompleted = true; + return progress; + } + + progress.IsCompleted = item.IsCompleted; + progress.Progress = (int)item.Percentage; + + if (item.IsCompleted) + { + _progressQueue.DequeueTask(item.Id); + } + + return progress; + } + + + public UsersQuotaSyncOperation(IServiceProvider serviceProvider, IDistributedTaskQueueFactory queueFactory) + { + _serviceProvider = serviceProvider; + _progressQueue = queueFactory.CreateQueue(CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME); + } + + + + public static class UsersQuotaOperationExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + } + } +} + +public class UsersQuotaSyncJob : DistributedTaskProgress +{ + private readonly IServiceScopeFactory _serviceScopeFactory; + + protected readonly IDbContextFactory _dbContextFactory; + + + private int? _tenantId; + public int TenantId + { + get + { + return _tenantId ?? this[nameof(_tenantId)]; + } + private set + { + _tenantId = value; + this[nameof(_tenantId)] = value; + } + } + + public UsersQuotaSyncJob(IServiceScopeFactory serviceScopeFactory) + { + _serviceScopeFactory = serviceScopeFactory; + } + + public void InitJob(Tenant tenant) + { + TenantId = tenant.Id; + } + + public async Task RunJobAsync(DistributedTask _, CancellationToken cancellationToken) + { + try + { + using var scope = _serviceScopeFactory.CreateScope(); + + var _tenantManager = scope.ServiceProvider.GetRequiredService(); + var _userManager = scope.ServiceProvider.GetRequiredService(); + var _authentication = scope.ServiceProvider.GetRequiredService(); + var _securityContext = scope.ServiceProvider.GetRequiredService(); + var _webItemManagerSecurity = scope.ServiceProvider.GetRequiredService(); + + _tenantManager.SetCurrentTenant(TenantId); + + var users = _userManager.GetUsers(); + var webItems = _webItemManagerSecurity.GetItems(Web.Core.WebZones.WebZoneType.All, ItemAvailableState.All); + + foreach (var user in users) + { + if (cancellationToken.IsCancellationRequested) + { + Status = DistributedTaskStatus.Canceled; + break; + } + + Percentage += 1.0 * 100 / users.Length; + PublishChanges(); + + var account = _authentication.GetAccountByID(TenantId, user.Id); + _securityContext.AuthenticateMe(account); + + foreach (var item in webItems) + { + IUserSpaceUsage manager; + + if (item.ID == WebItemManager.DocumentsProductID) + { + manager = item.Context.SpaceUsageStatManager as IUserSpaceUsage; + if (manager == null) + { + continue; + } + await manager.RecalculateUserQuota(TenantId, user.Id); + } + } + + } + } + catch (Exception ex) + { + Status = DistributedTaskStatus.Failted; + Exception = ex; + } + finally + { + IsCompleted = true; + } + PublishChanges(); + } +} diff --git a/products/ASC.Files/Core/GlobalUsings.cs b/products/ASC.Files/Core/GlobalUsings.cs index 23f4d3c1fc..0bcb4a306e 100644 --- a/products/ASC.Files/Core/GlobalUsings.cs +++ b/products/ASC.Files/Core/GlobalUsings.cs @@ -54,6 +54,7 @@ global using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox; global using ASC.Api.Collections; global using ASC.Api.Core; +global using ASC.Api.Core.Model; global using ASC.Api.Core.Security; global using ASC.Api.Utils; global using ASC.AuditTrail; @@ -150,6 +151,7 @@ global using ASC.Web.Files.Services.WCFService.FileOperations; global using ASC.Web.Files.ThirdPartyApp; global using ASC.Web.Files.Utils; global using ASC.Web.Studio.Core; +global using ASC.Web.Studio.Core.Quota; global using ASC.Web.Studio.Core.Notify; global using ASC.Web.Studio.Utility; diff --git a/products/ASC.Files/Core/Helpers/Global.cs b/products/ASC.Files/Core/Helpers/Global.cs index fc27258374..fcc538d4f6 100644 --- a/products/ASC.Files/Core/Helpers/Global.cs +++ b/products/ASC.Files/Core/Helpers/Global.cs @@ -250,12 +250,12 @@ public class GlobalStore [Scope] public class GlobalSpace { - private readonly FilesUserSpaceUsage _filesUserSpaceUsage; + private readonly FilesSpaceUsageStatManager _filesSpaceUsageStatManager; private readonly AuthContext _authContext; - public GlobalSpace(FilesUserSpaceUsage filesUserSpaceUsage, AuthContext authContext) + public GlobalSpace(FilesSpaceUsageStatManager filesSpaceUsageStatManager, AuthContext authContext) { - _filesUserSpaceUsage = filesUserSpaceUsage; + _filesSpaceUsageStatManager = filesSpaceUsageStatManager; _authContext = authContext; } @@ -266,7 +266,7 @@ public class GlobalSpace public Task GetUserUsedSpaceAsync(Guid userId) { - return _filesUserSpaceUsage.GetUserSpaceUsageAsync(userId); + return _filesSpaceUsageStatManager.GetUserSpaceUsageAsync(userId); } } diff --git a/products/ASC.Files/Server/ProductEntryPoint.cs b/products/ASC.Files/Server/ProductEntryPoint.cs index 2d293d52d2..6e8c5d6ed2 100644 --- a/products/ASC.Files/Server/ProductEntryPoint.cs +++ b/products/ASC.Files/Server/ProductEntryPoint.cs @@ -35,13 +35,13 @@ public class ApiProductEntryPoint : ProductEntryPoint } public ApiProductEntryPoint( - //FilesSpaceUsageStatManager filesSpaceUsageStatManager, + FilesSpaceUsageStatManager filesSpaceUsageStatManager, CoreBaseSettings coreBaseSettings, AuthContext authContext, UserManager userManager, NotifyConfiguration notifyConfiguration //SubscriptionManager subscriptionManager - ) : base(coreBaseSettings, authContext, userManager, notifyConfiguration) + ) : base(filesSpaceUsageStatManager, coreBaseSettings, authContext, userManager, notifyConfiguration) { } diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs index 20e2e055e9..6ed7f134a3 100644 --- a/products/ASC.People/Server/Api/UserController.cs +++ b/products/ASC.People/Server/Api/UserController.cs @@ -33,7 +33,7 @@ public class UserController : PeopleControllerBase private Tenant Tenant => _apiContext.Tenant; private readonly ICache _cache; - private readonly TenantManager _tenantManager; + private readonly TenantManager _tenantManager; private readonly CookiesManager _cookiesManager; private readonly CoreBaseSettings _coreBaseSettings; private readonly CustomNamingPeople _customNamingPeople; @@ -59,15 +59,16 @@ public class UserController : PeopleControllerBase private readonly SetupInfo _setupInfo; private readonly SettingsManager _settingsManager; private readonly RoomLinkService _roomLinkService; - private readonly FileSecurity _fileSecurity; - private readonly IQuotaService _quotaService; + private readonly FileSecurity _fileSecurity; + private readonly IQuotaService _quotaService; private readonly CountRoomAdminChecker _countRoomAdminChecker; + private readonly UsersQuotaSyncOperation _usersQuotaSyncOperation; private readonly CountUserChecker _countUserChecker; private readonly UsersInRoomChecker _usersInRoomChecker; public UserController( ICache cache, - TenantManager tenantManager, + TenantManager tenantManager, CookiesManager cookiesManager, CoreBaseSettings coreBaseSettings, CustomNamingPeople customNamingPeople, @@ -98,8 +99,9 @@ public class UserController : PeopleControllerBase IHttpClientFactory httpClientFactory, IHttpContextAccessor httpContextAccessor, SettingsManager settingsManager, - RoomLinkService roomLinkService, + RoomLinkService roomLinkService, FileSecurity fileSecurity, + UsersQuotaSyncOperation usersQuotaSyncOperation, CountRoomAdminChecker countRoomAdminChecker, CountUserChecker activeUsersChecker, UsersInRoomChecker usersInRoomChecker, @@ -107,7 +109,7 @@ public class UserController : PeopleControllerBase : base(userManager, permissionContext, apiContext, userPhotoManager, httpClientFactory, httpContextAccessor) { _cache = cache; - _tenantManager = tenantManager; + _tenantManager = tenantManager; _cookiesManager = cookiesManager; _coreBaseSettings = coreBaseSettings; _customNamingPeople = customNamingPeople; @@ -133,11 +135,12 @@ public class UserController : PeopleControllerBase _setupInfo = setupInfo; _settingsManager = settingsManager; _roomLinkService = roomLinkService; - _fileSecurity = fileSecurity; + _fileSecurity = fileSecurity; _countRoomAdminChecker = countRoomAdminChecker; _countUserChecker = activeUsersChecker; _usersInRoomChecker = usersInRoomChecker; _quotaService = quotaService; + _usersQuotaSyncOperation = usersQuotaSyncOperation; } [HttpPost("active")] @@ -203,27 +206,27 @@ public class UserController : PeopleControllerBase { _apiContext.AuthByClaim(); - _permissionContext.DemandPermissions(Constants.Action_AddRemoveUser); - + _permissionContext.DemandPermissions(Constants.Action_AddRemoveUser); + var options = inDto.FromInviteLink ? await _roomLinkService.GetOptionsAsync(inDto.Key, inDto.Email, inDto.Type) : null; if (options != null && !options.IsCorrect) - { + { throw new SecurityException(FilesCommonResource.ErrorMessage_InvintationLink); } - + inDto.Type = options != null ? options.EmployeeType : inDto.Type; var user = new UserInfo(); - + var byEmail = options?.LinkType == LinkType.InvintationByEmail; if (byEmail) - { + { user = _userManager.GetUserByEmail(inDto.Email); - + if (user == Constants.LostUser || user.ActivationStatus != EmployeeActivationStatus.Pending) - { + { throw new SecurityException(FilesCommonResource.ErrorMessage_InvintationLink); } } @@ -270,26 +273,26 @@ public class UserController : PeopleControllerBase if (inDto.Files != _userPhotoManager.GetDefaultPhotoAbsoluteWebPath()) { await UpdatePhotoUrl(inDto.Files, user); - } - + } + if (options != null && options.LinkType == LinkType.InvintationToRoom) { var success = int.TryParse(options.RoomId, out var id); if (success) - { + { await _usersInRoomChecker.CheckAppend(); await _fileSecurity.ShareAsync(id, FileEntryType.Folder, user.Id, options.Share); } else - { + { await _usersInRoomChecker.CheckAppend(); await _fileSecurity.ShareAsync(options.RoomId, FileEntryType.Folder, user.Id, options.Share); } } var messageAction = inDto.IsUser ? MessageAction.GuestCreated : MessageAction.UserCreated; - _messageService.Send(messageAction, _messageTarget.Create(user.Id), user.DisplayUserName(false, _displayUserSettingsHelper)); + _messageService.Send(messageAction, _messageTarget.Create(user.Id), user.DisplayUserName(false, _displayUserSettingsHelper)); return await _employeeFullDtoHelper.GetFull(user); } @@ -494,7 +497,7 @@ public class UserController : PeopleControllerBase return await _employeeFullDtoHelper.GetFull(user); } - + [AllowNotPayment] [Authorize(AuthenticationSchemes = "confirm", Roles = "LinkInvite,Everyone")] [HttpGet("{username}", Order = 1)] @@ -700,7 +703,7 @@ public class UserController : PeopleControllerBase _userManager.IsUser(user) ? EmployeeType.User : EmployeeType.RoomAdmin; _studioNotifyService.SendDocSpaceInvite(user.Email, _roomLinkService.GetInvitationLink(user.Email, type, _authContext.CurrentAccount.ID)); - } + } else { _studioNotifyService.SendEmailActivationInstructions(user, user.Email); @@ -732,7 +735,7 @@ public class UserController : PeopleControllerBase _settingsManager.SaveForCurrentUser(darkThemeSettings); return darkThemeSettings; - } + } [AllowNotPayment] [HttpGet("@self")] @@ -965,14 +968,14 @@ public class UserController : PeopleControllerBase var canBeGuestFlag = !user.IsOwner(Tenant) && !_userManager.IsDocSpaceAdmin(user) && user.GetListAdminModules(_webItemSecurity, _webItemManager).Count == 0 && !user.IsMe(_authContext); if (inDto.IsUser && !_userManager.IsUser(user) && canBeGuestFlag) - { + { await _countUserChecker.CheckAppend(); _userManager.AddUserIntoGroup(user.Id, Constants.GroupUser.ID); _webItemSecurityCache.ClearCache(Tenant.Id); } if (!self && !inDto.IsUser && _userManager.IsUser(user)) - { + { await _countRoomAdminChecker.CheckAppend(); _userManager.RemoveUserFromGroup(user.Id, Constants.GroupUser.ID); _webItemSecurityCache.ClearCache(Tenant.Id); @@ -1010,11 +1013,11 @@ public class UserController : PeopleControllerBase { case EmployeeStatus.Active: if (user.Status == EmployeeStatus.Terminated) - { + { if (!_userManager.IsUser(user)) - { + { await _countRoomAdminChecker.CheckAppend(); - } + } else { await _countUserChecker.CheckAppend(); @@ -1079,8 +1082,21 @@ public class UserController : PeopleControllerBase { yield return await _employeeFullDtoHelper.GetFull(user); } - } - + } + [HttpGet("recalculatequota")] + public void RecalculateQuota() + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + _usersQuotaSyncOperation.RecalculateQuota(_tenantManager.GetCurrentTenant()); + } + + [HttpGet("checkrecalculatequota")] + public TaskProgressDto CheckRecalculateQuota() + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + return _usersQuotaSyncOperation.CheckRecalculateQuota(_tenantManager.GetCurrentTenant()); + } + [HttpPut("quota")] public async IAsyncEnumerable UpdateUserQuota(UpdateMembersQuotaRequestDto inDto) { @@ -1094,7 +1110,7 @@ public class UserController : PeopleControllerBase if (inDto.Quota != -1) { var usedSpace = Math.Max(0, - _quotaService.FindUserQuotaRows( + _quotaService.FindUserQuotaRows( _tenantManager.GetCurrentTenant().Id, user.Id ) diff --git a/products/ASC.People/Server/GlobalUsings.cs b/products/ASC.People/Server/GlobalUsings.cs index cab2cc2134..6d028ab8e7 100644 --- a/products/ASC.People/Server/GlobalUsings.cs +++ b/products/ASC.People/Server/GlobalUsings.cs @@ -31,6 +31,7 @@ global using System.ServiceModel.Security; global using System.Web; global using ASC.Api.Core; +global using ASC.Api.Core.Model; global using ASC.Api.Core.Convention; global using ASC.Api.Core.Extensions; global using ASC.Api.Utils; @@ -73,6 +74,7 @@ global using ASC.Web.Core.PublicResources; global using ASC.Web.Core.Quota; global using ASC.Web.Core.Users; global using ASC.Web.Core.Utility; +global using ASC.Web.Files; global using ASC.Web.Files.Classes; global using ASC.Web.Studio.Core; global using ASC.Web.Studio.Core.Notify; diff --git a/web/ASC.Web.Core/SpaceUsageStatManager.cs b/web/ASC.Web.Core/SpaceUsageStatManager.cs index 689c5eaca3..fd2b58b4ca 100644 --- a/web/ASC.Web.Core/SpaceUsageStatManager.cs +++ b/web/ASC.Web.Core/SpaceUsageStatManager.cs @@ -43,4 +43,6 @@ public abstract class SpaceUsageStatManager public interface IUserSpaceUsage { Task GetUserSpaceUsageAsync(Guid userId); + + Task RecalculateUserQuota(int tenantId, Guid userId); }