Merge pull request #1727 from ONLYOFFICE/feature/accounts-optimization
Feature/accounts optimization
This commit is contained in:
commit
00a9b332df
@ -181,7 +181,21 @@ public class CachedUserService : IUserService, ICachedService
|
||||
CacheUserGroupRefItem = userServiceCache.CacheUserGroupRefItem;
|
||||
}
|
||||
|
||||
public IQueryable<UserInfo> GetUsers(
|
||||
public Task<int> GetUsersCountAsync(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
List<Guid> excludeGroups,
|
||||
List<Tuple<List<List<Guid>>, List<Guid>>> combinedGroups,
|
||||
EmployeeActivationStatus? activationStatus,
|
||||
AccountLoginType? accountLoginType,
|
||||
string text)
|
||||
{
|
||||
return Service.GetUsersCountAsync(tenant, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<UserInfo> GetUsers(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
@ -194,11 +208,9 @@ public class CachedUserService : IUserService, ICachedService
|
||||
string sortBy,
|
||||
bool sortOrderAsc,
|
||||
long limit,
|
||||
long offset,
|
||||
out int total,
|
||||
out int count)
|
||||
long offset)
|
||||
{
|
||||
return Service.GetUsers(tenant, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text, sortBy, sortOrderAsc, limit, offset, out total, out count);
|
||||
return Service.GetUsers(tenant, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text, sortBy, sortOrderAsc, limit, offset);
|
||||
}
|
||||
|
||||
public async Task<UserInfo> GetUserAsync(int tenant, Guid id)
|
||||
|
@ -180,8 +180,21 @@ public class UserManager
|
||||
|
||||
return await users.ToArrayAsync();
|
||||
}
|
||||
|
||||
public Task<int> GetUsersCountAsync(
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
List<Guid> excludeGroups,
|
||||
List<Tuple<List<List<Guid>>, List<Guid>>> combinedGroups,
|
||||
EmployeeActivationStatus? activationStatus,
|
||||
AccountLoginType? accountLoginType,
|
||||
string text)
|
||||
{
|
||||
return _userService.GetUsersCountAsync(Tenant.Id, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text);
|
||||
}
|
||||
|
||||
public IQueryable<UserInfo> GetUsers(
|
||||
public IAsyncEnumerable<UserInfo> GetUsers(
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
@ -193,11 +206,9 @@ public class UserManager
|
||||
string sortBy,
|
||||
bool sortOrderAsc,
|
||||
long limit,
|
||||
long offset,
|
||||
out int total,
|
||||
out int count)
|
||||
long offset)
|
||||
{
|
||||
return _userService.GetUsers(Tenant.Id, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text, sortBy, sortOrderAsc, limit, offset, out total, out count);
|
||||
return _userService.GetUsers(Tenant.Id, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text, sortBy, sortOrderAsc, limit, offset);
|
||||
}
|
||||
|
||||
public async Task<string[]> GetUserNamesAsync(EmployeeStatus status)
|
||||
|
@ -30,7 +30,19 @@ namespace ASC.Core;
|
||||
public interface IUserService
|
||||
{
|
||||
Task<IEnumerable<UserInfo>> GetUsersAsync(int tenant);
|
||||
IQueryable<UserInfo> GetUsers(int tenant, bool isDocSpaceAdmin,
|
||||
Task<int> GetUsersCountAsync(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
List<Guid> excludeGroups,
|
||||
List<Tuple<List<List<Guid>>, List<Guid>>> combinedGroups,
|
||||
EmployeeActivationStatus? activationStatus,
|
||||
AccountLoginType? accountLoginType,
|
||||
string text);
|
||||
IAsyncEnumerable<UserInfo> GetUsers(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
List<Guid> excludeGroups,
|
||||
@ -41,9 +53,7 @@ public interface IUserService
|
||||
string sortBy,
|
||||
bool sortOrderAsc,
|
||||
long limit,
|
||||
long offset,
|
||||
out int total,
|
||||
out int count);
|
||||
long offset);
|
||||
Task<byte[]> GetUserPhotoAsync(int tenant, Guid id);
|
||||
Task<DateTime> GetUserPasswordStampAsync(int tenant, Guid id);
|
||||
Task<Group> GetGroupAsync(int tenant, Guid id);
|
||||
@ -69,4 +79,4 @@ public interface IUserService
|
||||
Task RemoveUserGroupRefAsync(int tenant, Guid userId, Guid groupId, UserGroupRefType refType);
|
||||
Task SetUserPasswordHashAsync(int tenant, Guid id, string passwordHash);
|
||||
Task SetUserPhotoAsync(int tenant, Guid id, byte[] photo);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,11 @@ public class EFUserService : IUserService
|
||||
private readonly MachinePseudoKeys _machinePseudoKeys;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
private static readonly Expression<Func<UserWithGroup, int>> _orderByUserType = u =>
|
||||
u.Group == null ? 2 :
|
||||
u.Group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 :
|
||||
u.Group.UserGroupId == Users.Constants.GroupCollaborator.ID ? 3 : 4;
|
||||
|
||||
public EFUserService(
|
||||
IDbContextFactory<UserDbContext> dbContextFactory,
|
||||
MachinePseudoKeys machinePseudoKeys,
|
||||
@ -232,7 +237,27 @@ public class EFUserService : IUserService
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public IQueryable<UserInfo> GetUsers(
|
||||
public async Task<int> GetUsersCountAsync(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
List<List<Guid>> includeGroups,
|
||||
List<Guid> excludeGroups,
|
||||
List<Tuple<List<List<Guid>>, List<Guid>>> combinedGroups,
|
||||
EmployeeActivationStatus? activationStatus,
|
||||
AccountLoginType? accountLoginType,
|
||||
string text)
|
||||
{
|
||||
await using var userDbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var q = GetUserQuery(userDbContext, tenant);
|
||||
|
||||
q = GetUserQueryForFilter(userDbContext, q, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text);
|
||||
|
||||
return await q.CountAsync();
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<UserInfo> GetUsers(
|
||||
int tenant,
|
||||
bool isDocSpaceAdmin,
|
||||
EmployeeStatus? employeeStatus,
|
||||
@ -245,49 +270,34 @@ public class EFUserService : IUserService
|
||||
string sortBy,
|
||||
bool sortOrderAsc,
|
||||
long limit,
|
||||
long offset,
|
||||
out int total,
|
||||
out int count)
|
||||
long offset)
|
||||
{
|
||||
var userDbContext = _dbContextFactory.CreateDbContext();
|
||||
var totalQuery = GetUserQuery(userDbContext, tenant);
|
||||
totalQuery = GetUserQueryForFilter(userDbContext, totalQuery, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text);
|
||||
total = totalQuery.Count();
|
||||
if (limit <= 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
await using var userDbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var q = GetUserQuery(userDbContext, tenant);
|
||||
|
||||
q = GetUserQueryForFilter(userDbContext, q, isDocSpaceAdmin, employeeStatus, includeGroups, excludeGroups, combinedGroups, activationStatus, accountLoginType, text);
|
||||
|
||||
var orderedQuery = q.OrderBy(r => r.ActivationStatus == EmployeeActivationStatus.Pending);
|
||||
var orderedQuery = q.OrderBy(r => r.ActivationStatus);
|
||||
q = orderedQuery;
|
||||
|
||||
if (!string.IsNullOrEmpty(sortBy))
|
||||
{
|
||||
if (sortBy == "type")
|
||||
{
|
||||
var q1 = from user in q
|
||||
join userGroup in userDbContext.UserGroups.Where(g => !g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID
|
||||
|| g.UserGroupId == Users.Constants.GroupCollaborator.ID))
|
||||
on user.Id equals userGroup.Userid into joinedGroup
|
||||
from @group in joinedGroup.DefaultIfEmpty()
|
||||
select new { user, @group };
|
||||
var q1 = (from user in q
|
||||
join userGroup in userDbContext.UserGroups.Where(g =>
|
||||
!g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID ||
|
||||
g.UserGroupId == Users.Constants.GroupCollaborator.ID)) on user.Id equals userGroup.Userid into joinedGroup
|
||||
from @group in joinedGroup.DefaultIfEmpty()
|
||||
select new UserWithGroup { User = user, Group = @group }).OrderBy(r => r.User.ActivationStatus);
|
||||
|
||||
if (sortOrderAsc)
|
||||
{
|
||||
q = q1.OrderBy(r => r.user.ActivationStatus == EmployeeActivationStatus.Pending)
|
||||
.ThenBy(r => r.group == null ? 2 :
|
||||
r.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 :
|
||||
r.group.UserGroupId == Users.Constants.GroupCollaborator.ID ? 3 : 4)
|
||||
.Select(r => r.user);
|
||||
}
|
||||
else
|
||||
{
|
||||
q = q1.OrderBy(r => r.user.ActivationStatus == EmployeeActivationStatus.Pending)
|
||||
.ThenByDescending(u => u.group == null ? 2 :
|
||||
u.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 :
|
||||
u.group.UserGroupId == Users.Constants.GroupCollaborator.ID ? 3 : 4)
|
||||
.Select(r => r.user);
|
||||
}
|
||||
q = (sortOrderAsc ? q1.ThenBy(_orderByUserType) : q1.ThenByDescending(_orderByUserType)).Select(r => r.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -295,19 +305,17 @@ public class EFUserService : IUserService
|
||||
}
|
||||
}
|
||||
|
||||
if (offset != 0)
|
||||
if (offset > 0)
|
||||
{
|
||||
q = q.Skip((int)offset);
|
||||
}
|
||||
|
||||
if (limit != 0)
|
||||
q = q.Take((int)limit);
|
||||
|
||||
await foreach (var user in q.ToAsyncEnumerable())
|
||||
{
|
||||
q = q.Take((int)limit);
|
||||
yield return _mapper.Map<User, UserInfo>(user);
|
||||
}
|
||||
|
||||
count = q.Count();
|
||||
|
||||
return q.ProjectTo<UserInfo>(_mapper.ConfigurationProvider);
|
||||
}
|
||||
|
||||
public IQueryable<UserInfo> GetUsers(int tenant, out int total)
|
||||
@ -793,6 +801,12 @@ public class DbUserSecurity
|
||||
public UserSecurity UserSecurity { get; set; }
|
||||
}
|
||||
|
||||
public class UserWithGroup
|
||||
{
|
||||
public User User { get; set; }
|
||||
public UserGroup Group { get; set; }
|
||||
}
|
||||
|
||||
static file class Queries
|
||||
{
|
||||
public static readonly Func<UserDbContext, int, Guid, Task<DateTime?>> LastModifiedAsync =
|
||||
|
@ -109,6 +109,15 @@ public static class DbUserExtension
|
||||
entity.HasIndex(e => new { e.TenantId, e.UserName })
|
||||
.HasDatabaseName("username");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.FirstName })
|
||||
.HasDatabaseName("tenant_activation_status_firstname");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.LastName })
|
||||
.HasDatabaseName("tenant_activation_status_lastname");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.Email })
|
||||
.HasDatabaseName("tenant_activation_status_email");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("varchar(38)")
|
||||
@ -257,6 +266,15 @@ public static class DbUserExtension
|
||||
|
||||
entity.HasIndex(e => new { e.UserName, e.TenantId })
|
||||
.HasDatabaseName("username");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.FirstName })
|
||||
.HasDatabaseName("tenant_activation_status_firstname");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.LastName })
|
||||
.HasDatabaseName("tenant_activation_status_lastname");
|
||||
|
||||
entity.HasIndex(e => new { e.TenantId, e.ActivationStatus, e.Email })
|
||||
.HasDatabaseName("tenant_activation_status_email");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasColumnName("id")
|
||||
|
7164
migrations/mysql/SaaS/MigrationContext/20230906082838_MigrationContext_Upgrade3.Designer.cs
generated
Normal file
7164
migrations/mysql/SaaS/MigrationContext/20230906082838_MigrationContext_Upgrade3.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ASC.Migrations.MySql.SaaS.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class MigrationContext_Upgrade3 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "tenant_activation_status_email",
|
||||
table: "core_user",
|
||||
columns: new[] { "tenant", "activation_status", "email" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "tenant_activation_status_firstname",
|
||||
table: "core_user",
|
||||
columns: new[] { "tenant", "activation_status", "firstname" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "tenant_activation_status_lastname",
|
||||
table: "core_user",
|
||||
columns: new[] { "tenant", "activation_status", "lastname" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "tenant_activation_status_email",
|
||||
table: "core_user");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "tenant_activation_status_firstname",
|
||||
table: "core_user");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "tenant_activation_status_lastname",
|
||||
table: "core_user");
|
||||
}
|
||||
}
|
||||
}
|
@ -5125,6 +5125,15 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
|
||||
b.HasIndex("TenantId", "UserName")
|
||||
.HasDatabaseName("username");
|
||||
|
||||
b.HasIndex("TenantId", "ActivationStatus", "Email")
|
||||
.HasDatabaseName("tenant_activation_status_email");
|
||||
|
||||
b.HasIndex("TenantId", "ActivationStatus", "FirstName")
|
||||
.HasDatabaseName("tenant_activation_status_firstname");
|
||||
|
||||
b.HasIndex("TenantId", "ActivationStatus", "LastName")
|
||||
.HasDatabaseName("tenant_activation_status_lastname");
|
||||
|
||||
b.ToTable("core_user", (string)null);
|
||||
|
||||
b.HasAnnotation("MySql:CharSet", "utf8");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -171,11 +171,12 @@ public class UserPhotoManagerCache
|
||||
return null;
|
||||
}
|
||||
|
||||
if (size != Size.Empty && !val.TryGetValue(UserPhotoManager.ToCache(size), out fileName))
|
||||
if (!val.TryGetValue(UserPhotoManager.ToCache(size), out fileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (String.IsNullOrEmpty(fileName))
|
||||
|
||||
if (String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = val.Values.FirstOrDefault(x => !string.IsNullOrEmpty(x) && x.Contains("_orig_"));
|
||||
}
|
||||
@ -562,6 +563,9 @@ public class UserPhotoManager
|
||||
|
||||
await Task.WhenAll(t1, t2, t3, t4, t5);
|
||||
}
|
||||
|
||||
_userPhotoManagerCache.AddToCache(userID, Size.Empty, fileName, await _tenantManager.GetCurrentTenantIdAsync());
|
||||
|
||||
return (photoUrl, fileName);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user