{item.user}
@@ -40,16 +38,14 @@ export const AuditContent = ({ sectionWidth, item, isSettingNotPaid }) => {
fontSize="12px"
fontWeight={600}
truncate={true}
- className="settings_unavailable"
- >
+ className="settings_unavailable">
{dateStr}
+ className="settings_unavailable">
{`${item.context ? item.context + " |" : ""} ${item.action}`}
diff --git a/packages/client/src/store/FilesStore.js b/packages/client/src/store/FilesStore.js
index 3590b61f33..58317cc366 100644
--- a/packages/client/src/store/FilesStore.js
+++ b/packages/client/src/store/FilesStore.js
@@ -30,6 +30,7 @@ import { getContextMenuKeysByType } from "SRC_DIR/helpers/plugins";
import { PluginContextMenuItemType } from "SRC_DIR/helpers/plugins/constants";
import { CategoryType } from "SRC_DIR/helpers/constants";
import debounce from "lodash.debounce";
+import clone from "lodash/clone";
import Queue from "queue-promise";
const { FilesFilter, RoomsFilter } = api;
@@ -80,8 +81,9 @@ class FilesStore {
bufferSelection = null;
selected = "close";
- filter = FilesFilter.getDefault(); //TODO: FILTER
+ filter = FilesFilter.getDefault();
roomsFilter = RoomsFilter.getDefault();
+ membersFilter = { page: 0, pageCount: 100, total: 0 };
categoryType = getCategoryType(window.location);
@@ -2426,9 +2428,48 @@ class FilesStore {
return api.rooms.removeLogoFromRoom(id);
}
- getRoomMembers(id) {
- return api.rooms.getRoomMembers(id);
- }
+ getDefaultMembersFilter = () => {
+ return { page: 0, pageCount: 100, total: 0 };
+ };
+
+ setRoomMembersFilter = (roomMembersFilter) => {
+ this.roomMembersFilter = roomMembersFilter;
+ };
+
+ getRoomMembers = (id, clearFilter = true) => {
+ let newFilter = this.membersFilter;
+
+ if (clearFilter) {
+ newFilter = this.getDefaultMembersFilter();
+ } else {
+ newFilter.page += 1;
+ }
+ this.setRoomMembersFilter(newFilter);
+
+ const membersFilters = {
+ startIndex: newFilter.page * newFilter.pageCount,
+ count: newFilter.pageCount,
+ filterType: 0, // 0 (Members)
+ };
+
+ return api.rooms.getRoomMembers(id, membersFilters).then((res) => {
+ const newFilter = clone(this.membersFilter);
+ newFilter.total = res.total;
+ this.setMembersFilter(newFilter);
+
+ return res.items;
+ });
+ };
+
+ setMembersFilter = (filter) => {
+ this.membersFilter = filter;
+ };
+
+ getRoomLinks = (id) => {
+ return api.rooms
+ .getRoomMembers(id, { filterType: 2 }) // 2 (External link)
+ .then((res) => res.items);
+ };
updateRoomMemberRole(id, data) {
return api.rooms.updateRoomMemberRole(id, data);
@@ -3623,16 +3664,16 @@ class FilesStore {
return Math.floor(sectionWidth / minTileWidth);
};
- setInvitationLinks = async (roomId, linkId, title, access) => {
+ setInvitationLinks = async (roomId, title, access, linkId) => {
return await api.rooms.setInvitationLinks(roomId, linkId, title, access);
};
- resendEmailInvitations = async (id, usersIds) => {
- return await api.rooms.resendEmailInvitations(id, usersIds);
+ resendEmailInvitations = async (id, resendAll) => {
+ return await api.rooms.resendEmailInvitations(id, resendAll);
};
getRoomSecurityInfo = async (id) => {
- return await api.rooms.getRoomSecurityInfo(id);
+ return await api.rooms.getRoomSecurityInfo(id).then((res) => res.items);
};
setRoomSecurity = async (id, data) => {
diff --git a/packages/client/src/store/PublicRoomStore.js b/packages/client/src/store/PublicRoomStore.js
index 089acd0e84..7bb05fef43 100644
--- a/packages/client/src/store/PublicRoomStore.js
+++ b/packages/client/src/store/PublicRoomStore.js
@@ -45,12 +45,25 @@ class PublicRoomStore {
this.externalLinks = externalLinks;
};
- setExternalLink = (linkId, data) => {
- const linkIndex = this.externalLinks.findIndex(
- (l) => l.sharedTo.id === linkId
+ deleteExternalLink = (linkId) => {
+ const externalLinks = this.externalLinks.filter(
+ (l) => l.sharedTo.id !== linkId
);
- const dataLink = data.find((l) => l.sharedTo.id === linkId);
- this.externalLinks[linkIndex] = dataLink;
+ this.externalLinks = externalLinks;
+ };
+
+ setExternalLink = (link) => {
+ const linkIndex = this.externalLinks.findIndex(
+ (l) => l.sharedTo.id === link.sharedTo.id
+ );
+ const externalLinks = this.externalLinks;
+
+ if (linkIndex === -1) {
+ externalLinks.push(link);
+ this.externalLinks = externalLinks;
+ } else {
+ externalLinks[linkIndex] = link;
+ }
};
setExternalLinks = (links) => {
diff --git a/packages/common/api/people/index.js b/packages/common/api/people/index.js
index fe1c6dd8f6..5c3ae55094 100644
--- a/packages/common/api/people/index.js
+++ b/packages/common/api/people/index.js
@@ -358,3 +358,36 @@ export function getUsersByQuery(query) {
url: `/people/search?query=${query}`,
});
}
+
+export function getMembersList(roomId, filter = Filter.getDefault()) {
+ let params = "";
+
+ if (filter) {
+ checkFilterInstance(filter, Filter);
+
+ params = `?${filter.toApiUrlParams(
+ "id,email,avatar,icon,displayName,hasAvatar,isOwner,isAdmin,isVisitor,isCollaborator,"
+ )}`;
+ }
+
+ const excludeShared = filter.excludeShared ? filter.excludeShared : false;
+
+ if (params) {
+ params += `&excludeShared=${excludeShared}`;
+ } else {
+ params = `excludeShared=${excludeShared}`;
+ }
+
+ return request({
+ method: "get",
+ url: `people/room/${roomId}${params}`,
+ }).then((res) => {
+ res.items = res.items.map((user) => {
+ if (user && user.displayName) {
+ user.displayName = Encoder.htmlDecode(user.displayName);
+ }
+ return user;
+ });
+ return res;
+ });
+}
diff --git a/packages/common/api/rooms/index.js b/packages/common/api/rooms/index.js
index 6e4e3a49b9..12ec2c4e11 100644
--- a/packages/common/api/rooms/index.js
+++ b/packages/common/api/rooms/index.js
@@ -1,5 +1,9 @@
import { request } from "../client";
-import { checkFilterInstance, decodeDisplayName } from "../../utils";
+import {
+ checkFilterInstance,
+ decodeDisplayName,
+ toUrlParams,
+} from "../../utils";
import { FolderType } from "../../constants";
import RoomsFilter from "./filter";
@@ -45,10 +49,17 @@ export function getRoomInfo(id) {
});
}
-export function getRoomMembers(id) {
+export function getRoomMembers(id, filter) {
+ let params = "";
+ const str = toUrlParams(filter);
+
+ if (str) {
+ params = `?${str}`;
+ }
+
const options = {
method: "get",
- url: `/files/rooms/${id}/share`,
+ url: `/files/rooms/${id}/share${params}`,
};
return request(options).then((res) => {
@@ -288,12 +299,12 @@ export const setInvitationLinks = async (roomId, linkId, title, access) => {
return res;
};
-export const resendEmailInvitations = async (id, usersIds) => {
+export const resendEmailInvitations = async (id, resendAll = true) => {
const options = {
method: "post",
url: `/files/rooms/${id}/resend`,
data: {
- usersIds,
+ resendAll,
},
};
@@ -302,10 +313,11 @@ export const resendEmailInvitations = async (id, usersIds) => {
return res;
};
+//// 1 (Invitation link)
export const getRoomSecurityInfo = async (id) => {
const options = {
method: "get",
- url: `/files/rooms/${id}/share`,
+ url: `/files/rooms/${id}/share?filterType=1`,
};
const res = await request(options);
diff --git a/packages/components/submenu/index.js b/packages/components/submenu/index.js
index cc1c4ec3dd..f2b9242157 100644
--- a/packages/components/submenu/index.js
+++ b/packages/components/submenu/index.js
@@ -21,6 +21,7 @@ const Submenu = (props) => {
startSelect = 0,
forsedActiveItemId,
onSelect,
+ size,
...rest
} = props;
if (!data) return null;
@@ -105,7 +106,7 @@ const Submenu = (props) => {
-
+
{data.map((d) => {
const isActive =
@@ -144,9 +145,14 @@ const Submenu = (props) => {
);
})}
+ {size !== "scale" && (
+
+ )}
-
+ {size === "scale" && (
+
+ )}
@@ -164,6 +170,8 @@ Submenu.propTypes = {
startSelect: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
/** Property that allows explicitly selecting content passed through an external operation */
forsedActiveItemId: PropTypes.any,
+ /** Scales the width of the bottom line to 100%. */
+ size: PropTypes.string,
/** Sets a callback function that is triggered when the submenu item is selected */
onSelect: PropTypes.func,
};
diff --git a/packages/components/submenu/styled-submenu.js b/packages/components/submenu/styled-submenu.js
index 0c71ca21ae..28833502f1 100644
--- a/packages/components/submenu/styled-submenu.js
+++ b/packages/components/submenu/styled-submenu.js
@@ -128,6 +128,13 @@ export const SubmenuScroller = styled.div`
}
overflow-x: auto;
overflow-y: hidden;
+
+ ${(props) =>
+ props.size !== "scale" &&
+ css`
+ display: grid;
+ flex: 0 1 auto;
+ `}
`;
export const SubmenuRoot = styled.div`
diff --git a/products/ASC.Files/Core/ApiModels/RequestDto/UserInvintationRequestDto.cs b/products/ASC.Files/Core/ApiModels/RequestDto/UserInvitationRequestDto.cs
similarity index 95%
rename from products/ASC.Files/Core/ApiModels/RequestDto/UserInvintationRequestDto.cs
rename to products/ASC.Files/Core/ApiModels/RequestDto/UserInvitationRequestDto.cs
index c51d87103c..70e6b8548c 100644
--- a/products/ASC.Files/Core/ApiModels/RequestDto/UserInvintationRequestDto.cs
+++ b/products/ASC.Files/Core/ApiModels/RequestDto/UserInvitationRequestDto.cs
@@ -28,9 +28,10 @@ namespace ASC.Files.Core.ApiModels.RequestDto;
///
///
-public class UserInvintationRequestDto
+public class UserInvitationRequestDto
{
///
List of user IDs
///
System.Collections.Generic.IEnumerable{System.Guid}, System.Collections.Generic
public IEnumerable
UsersIds { get; set; }
+ public bool ResendAll { get; set; }
}
\ No newline at end of file
diff --git a/products/ASC.Files/Core/ApiModels/ResponseDto/FileShareDto.cs b/products/ASC.Files/Core/ApiModels/ResponseDto/FileShareDto.cs
index f121b919fb..3c38b93c07 100644
--- a/products/ASC.Files/Core/ApiModels/ResponseDto/FileShareDto.cs
+++ b/products/ASC.Files/Core/ApiModels/ResponseDto/FileShareDto.cs
@@ -74,7 +74,6 @@ public class FileShareLink
public string Password { get; set; }
public bool? Disabled { get; set; }
public bool? DenyDownload { get; set; }
- public bool IsTemplate { get; set; }
public bool? IsExpired { get; set; }
}
@@ -126,7 +125,6 @@ public class FileShareDtoHelper
Password = aceWrapper.FileShareOptions?.Password,
Disabled = aceWrapper.FileShareOptions?.Disabled is true ? true : expired,
DenyDownload = aceWrapper.FileShareOptions?.DenyDownload,
- IsTemplate = aceWrapper.IsTemplate,
LinkType = aceWrapper.SubjectType switch
{
SubjectType.InvitationLink => LinkType.Invitation,
diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/SecurityDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/SecurityDao.cs
index 5d88b564c8..6d6e1bf5b0 100644
--- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/SecurityDao.cs
+++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/SecurityDao.cs
@@ -24,6 +24,8 @@
// 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
+using User = ASC.Core.Common.EF.User;
+
namespace ASC.Files.Core.Data;
[Scope]
@@ -202,6 +204,164 @@ internal abstract class SecurityBaseDao : AbstractDao
return InternalGetPureShareRecordsAsync(entry);
}
+ public async Task GetPureSharesCountAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status)
+ {
+ if (entry == null)
+ {
+ return 0;
+ }
+
+ await using var filesDbContext = _dbContextFactory.CreateDbContext();
+
+ var q = await GetPureSharesQuery(entry, filterType, filesDbContext);
+
+ if (status.HasValue)
+ {
+ q = q.Join(filesDbContext.Users, s => s.Subject, u => u.Id,
+ (s, u) => new SecurityUserRecord { Security = s, User = u })
+ .Where(s => s.User.ActivationStatus == status.Value)
+ .Select(r => r.Security);
+ }
+
+ return await q.CountAsync();
+ }
+
+ public async IAsyncEnumerable GetPureSharesAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status, int offset = 0, int count = -1)
+ {
+ if (entry == null || count == 0)
+ {
+ yield break;
+ }
+
+ await using var filesDbContext = _dbContextFactory.CreateDbContext();
+
+ var q = await GetPureSharesQuery(entry, filterType, filesDbContext);
+
+ if (filterType == ShareFilterType.User)
+ {
+ var predicate = ShareCompareHelper.GetCompareExpression(s => s.Security.Share);
+
+ var q1 = q.Join(filesDbContext.Users, s => s.Subject, u => u.Id,
+ (s, u) => new SecurityUserRecord { Security = s, User = u });
+
+ if (status.HasValue)
+ {
+ q = q1.Where(s => s.User.ActivationStatus == status.Value)
+ .OrderBy(predicate)
+ .Select(s => s.Security);
+ }
+ else
+ {
+ q = q1.OrderBy(s => s.User.ActivationStatus)
+ .ThenBy(predicate)
+ .Select(s => s.Security);
+ }
+ }
+ else
+ {
+ var predicate = ShareCompareHelper.GetCompareExpression(s => s.Share);
+ q = q.OrderBy(predicate);
+ }
+
+ if (offset > 0)
+ {
+ q = q.Skip(offset);
+ }
+
+ if (count > 0)
+ {
+ q = q.Take(count);
+ }
+
+ await foreach (var r in q.ToAsyncEnumerable())
+ {
+ yield return await ToFileShareRecordAsync(r);
+ }
+ }
+
+ public async IAsyncEnumerable GetUsersWithSharedAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus,
+ bool excludeShared, int offset, int count)
+ {
+ if (entry == null || count == 0)
+ {
+ yield break;
+ }
+
+ await using var filesDbContext = _dbContextFactory.CreateDbContext();
+ var tenantId = TenantID;
+ var mappedId = (await MappingIDAsync(entry.Id)).ToString();
+
+ var q1 = GetUsersWithSharedQuery(tenantId, mappedId, entry, text, employeeStatus, activationStatus, excludeShared, filesDbContext);
+
+ if (offset > 0)
+ {
+ q1 = q1.Skip(offset);
+ }
+
+ if (count > 0)
+ {
+ q1 = q1.Take(count);
+ }
+
+ await foreach (var r in q1.ToAsyncEnumerable())
+ {
+ yield return new UserInfoWithShared { UserInfo = _mapper.Map(r.User), Shared = r.Shared };
+ }
+ }
+
+ public async Task GetUsersWithSharedCountAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus,
+ bool excludeShared)
+ {
+ if (entry == null)
+ {
+ return 0;
+ }
+
+ await using var filesDbContext = _dbContextFactory.CreateDbContext();
+ var tenantId = TenantID;
+ var mappedId = (await MappingIDAsync(entry.Id)).ToString();
+
+ var q1 = GetUsersWithSharedQuery(tenantId, mappedId, entry, text, employeeStatus, activationStatus, excludeShared, filesDbContext);
+
+ return await q1.CountAsync();
+ }
+
+ private static IQueryable GetUsersWithSharedQuery(int tenantId, string entryId, FileEntry entry, string text, EmployeeStatus? employeeStatus,
+ EmployeeActivationStatus? activationStatus, bool excludeShared, FilesDbContext filesDbContext)
+ {
+ var q = filesDbContext.Users.AsNoTracking().Where(u => u.TenantId == tenantId);
+
+ if (employeeStatus.HasValue)
+ {
+ q = q.Where(u => u.Status == employeeStatus.Value);
+ }
+
+ if (activationStatus.HasValue)
+ {
+ q = q.Where(u => u.ActivationStatus == activationStatus.Value);
+ }
+
+ if (!string.IsNullOrEmpty(text))
+ {
+ q = q.Where(u => u.FirstName.Contains(text) || u.LastName.Contains(text) || u.Email.Contains(text));
+ }
+
+ var q1 = excludeShared
+ ? q.Where(u => !filesDbContext.Security.Any(s => s.TenantId == tenantId && s.EntryType == entry.FileEntryType && s.EntryId == entryId && s.Subject == u.Id) &&
+ u.Id != entry.CreateBy)
+ .OrderBy(u => u.ActivationStatus)
+ .ThenBy(u => u.FirstName)
+ .Select(u => new UserWithShared { User = u, Shared = false })
+ : from user in q
+ join security in filesDbContext.Security.Where(s => s.TenantId == tenantId && s.EntryId == entryId && s.EntryType == entry.FileEntryType) on user.Id equals
+ security.Subject into grouping
+ from s in grouping.DefaultIfEmpty()
+ orderby user.ActivationStatus, user.FirstName
+ select new UserWithShared { User = user, Shared = s != null || user.Id == entry.CreateBy };
+
+ return q1;
+ }
+
internal async IAsyncEnumerable InternalGetPureShareRecordsAsync(FileEntry entry)
{
var files = new List();
@@ -234,6 +394,23 @@ internal abstract class SecurityBaseDao : AbstractDao
await filesDbContext.SaveChangesAsync();
}
+
+ public async IAsyncEnumerable GetPureSharesAsync(FileEntry entry, IEnumerable subjects)
+ {
+ if (subjects == null || !subjects.Any())
+ {
+ yield break;
+ }
+
+ var entryId = await MappingIDAsync(entry.Id);
+
+ await using var filesDbContext = _dbContextFactory.CreateDbContext();
+
+ await foreach (var security in Queries.EntrySharesBySubjectsAsync(filesDbContext, TenantID, entryId.ToString(), entry.FileEntryType, subjects))
+ {
+ yield return await ToFileShareRecordAsync(security);
+ }
+ }
internal async Task SelectFilesAndFoldersForShareAsync(FileEntry entry, ICollection files, ICollection folders, ICollection foldersInt)
{
@@ -294,6 +471,32 @@ internal abstract class SecurityBaseDao : AbstractDao
return result;
}
+
+ private async Task> GetPureSharesQuery(FileEntry entry, ShareFilterType filterType, FilesDbContext filesDbContext)
+ {
+ var entryId = await MappingIDAsync(entry.Id);
+
+ var q = filesDbContext.Security.AsNoTracking()
+ .Where(s => s.TenantId == TenantID && s.EntryId == entryId.ToString() && s.EntryType == entry.FileEntryType);
+
+ switch (filterType)
+ {
+ case ShareFilterType.User:
+ q = q.Where(s => s.SubjectType == SubjectType.User);
+ break;
+ case ShareFilterType.InvitationLink:
+ q = q.Where(s => s.SubjectType == SubjectType.InvitationLink);
+ break;
+ case ShareFilterType.ExternalLink:
+ q = q.Where(s => s.SubjectType == SubjectType.ExternalLink);
+ break;
+ case ShareFilterType.Link:
+ q = q.Where(s => s.SubjectType == SubjectType.InvitationLink || s.SubjectType == SubjectType.ExternalLink);
+ break;
+ }
+
+ return q;
+ }
}
[Scope]
@@ -547,6 +750,24 @@ internal class SecurityTreeRecord
public int Level { get; set; }
}
+public class SecurityUserRecord
+{
+ public DbFilesSecurity Security { get; init; }
+ public User User { get; init; }
+}
+
+public class UserInfoWithShared
+{
+ public UserInfo UserInfo { get; set; }
+ public bool Shared { get; set; }
+}
+
+public class UserWithShared
+{
+ public User User { get; set; }
+ public bool Shared { get; set; }
+}
+
static file class Queries
{
public static readonly Func>
@@ -616,4 +837,10 @@ static file class Queries
.Where(r => r.TenantId == tenantId
&& (r.Subject == subject || r.Owner == subject))
.ExecuteDelete());
+
+ public static readonly Func, IAsyncEnumerable> EntrySharesBySubjectsAsync =
+ Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
+ (FilesDbContext ctx, int tenantId, string entryId, FileEntryType entryType, IEnumerable subjects) =>
+ ctx.Security
+ .Where(r => r.TenantId == tenantId && r.EntryId == entryId && r.EntryType == entryType && subjects.Contains(r.Subject)));
}
\ No newline at end of file
diff --git a/products/ASC.Files/Core/Core/EF/FilesDbContext.cs b/products/ASC.Files/Core/Core/EF/FilesDbContext.cs
index 513dc710f9..3de523f589 100644
--- a/products/ASC.Files/Core/Core/EF/FilesDbContext.cs
+++ b/products/ASC.Files/Core/Core/EF/FilesDbContext.cs
@@ -24,6 +24,8 @@
// 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
+using User = ASC.Core.Common.EF.User;
+
namespace ASC.Files.Core.EF;
public class FilesDbContext : DbContext
@@ -42,6 +44,7 @@ public class FilesDbContext : DbContext
public DbSet FilesProperties { get; set; }
public DbSet Tenants { get; set; }
public DbSet FilesConverts { get; set; }
+ public DbSet Users { get; set; }
public FilesDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { }
@@ -63,6 +66,7 @@ public class FilesDbContext : DbContext
.AddDbFilesProperties()
.AddDbTenant()
.AddFilesConverts()
+ .AddUser()
.AddDbFunctions();
}
}
\ No newline at end of file
diff --git a/products/ASC.Files/Core/Core/FileStorageService.cs b/products/ASC.Files/Core/Core/FileStorageService.cs
index ce832aef4a..c5a95bbc13 100644
--- a/products/ASC.Files/Core/Core/FileStorageService.cs
+++ b/products/ASC.Files/Core/Core/FileStorageService.cs
@@ -533,7 +533,7 @@ public class FileStorageService //: IFileStorageService
var room = await InternalCreateNewFolderAsync(parentId, title, FolderType.PublicRoom, @private);
_ = await SetAceLinkAsync(room, SubjectType.ExternalLink, Guid.NewGuid(), FilesCommonResource.DefaultExternalLinkTitle, FileShare.Read, _actions[SubjectType.ExternalLink]);
-
+
return room;
}
@@ -2513,17 +2513,47 @@ public class FileStorageService //: IFileStorageService
public async Task> GetSharedInfoAsync(
IEnumerable fileIds,
IEnumerable folderIds,
- IEnumerable subjectTypes = null,
- bool withoutTemplates = false)
+ IEnumerable subjectTypes = null)
{
- return await _fileSharing.GetSharedInfoAsync(fileIds, folderIds, subjectTypes, withoutTemplates);
+ return await _fileSharing.GetSharedInfoAsync(fileIds, folderIds, subjectTypes);
+ }
+
+ public async Task> GetSharedInfoShortFileAsync(T fileId)
+ {
+ return await _fileSharing.GetSharedInfoShortFileAsync(fileId);
+ }
+
+ public async IAsyncEnumerable GetRoomSharedInfoAsync(T roomId, ShareFilterType filterType, int offset, int count)
+ {
+ var room = await GetFolderDao().GetFolderAsync(roomId).NotFoundIfNull();
+
+ await foreach (var ace in _fileSharing.GetRoomSharesAsync(room, filterType, null, offset, count))
+ {
+ yield return ace;
+ }
+ }
+
+ public async Task GetRoomSharesCountAsync(T roomId, ShareFilterType filterType)
+ {
+ var room = await GetFolderDao().GetFolderAsync(roomId).NotFoundIfNull();
+
+ return await _fileSharing.GetRoomSharesCountAsync(room, filterType);
+ }
+
+ public async IAsyncEnumerable GetSharedInfoAsync(T roomId, IEnumerable subjects)
+ {
+ var room = await GetFolderDao().GetFolderAsync(roomId).NotFoundIfNull();
+
+ await foreach (var ace in _fileSharing.GetPureSharesAsync(room, subjects))
+ {
+ yield return ace;
+ }
}
public async Task SetAceObjectAsync(AceCollection aceCollection, bool notify)
{
var fileDao = GetFileDao();
var folderDao = GetFolderDao();
- var securityDao = GetSecurityDao();
var entries = new List>();
string warning = null;
@@ -2542,77 +2572,49 @@ public class FileStorageService //: IFileStorageService
{
try
{
+ var result = await _fileSharingAceHelper.SetAceObjectAsync(aceCollection.Aces, entry, notify, aceCollection.Message, aceCollection.AdvancedSettings);
+ warning ??= result.Warning;
- var eventTypes = new List<(UserInfo User, EventType EventType, FileShare Access, string Email)>();
- foreach (var ace in aceCollection.Aces)
+ if (!result.Changed)
{
- var user = _userManager.GetUsers(ace.Id);
+ continue;
+ }
- if (user == Constants.LostUser)
+ foreach (var (eventType, ace) in result.HandledAces)
+ {
+ if (ace.IsLink)
{
- eventTypes.Add((null, EventType.Create, ace.Access, ace.Email));
continue;
}
- var userId = user.Id;
+ var user = !string.IsNullOrEmpty(ace.Email)
+ ? await _userManager.GetUserByEmailAsync(ace.Email)
+ : await _userManager.GetUsersAsync(ace.Id);
+
+ var name = user.DisplayUserName(false, _displayUserSettingsHelper);
- var userSubjects = await _fileSecurity.GetUserSubjectsAsync(user.Id);
- var usersRecords = await securityDao.GetSharesAsync(userSubjects).ToListAsync();
- var recordEntrys = usersRecords.Select(r => r.EntryId.ToString());
-
- EventType eventType;
-
- if (usersRecords.Any() && ace.Access != FileShare.None && recordEntrys.Contains(entry.Id.ToString()))
+ if (entry is Folder folder && DocSpaceHelper.IsRoom(folder.FolderType))
{
- eventType = EventType.Update;
- }
- else if (!usersRecords.Any() || !recordEntrys.Contains(entry.Id.ToString()))
- {
- eventType = EventType.Create;
+ switch (eventType)
+ {
+ case EventType.Create:
+ _ = _filesMessageService.SendAsync(MessageAction.RoomCreateUser, entry, user.Id, name, GetAccessString(ace.Access));
+ break;
+ case EventType.Remove:
+ _ = _filesMessageService.SendAsync(MessageAction.RoomRemoveUser, entry, user.Id, name, GetAccessString(ace.Access));
+ break;
+ case EventType.Update:
+ _ = _filesMessageService.SendAsync(MessageAction.RoomUpdateAccessForUser, entry, user.Id, ace.Access, name);
+ break;
+ }
}
else
{
- eventType = EventType.Remove;
- }
- eventTypes.Add((user, eventType, ace.Access, null));
- }
-
- var (changed, warningMessage) = await _fileSharingAceHelper.SetAceObjectAsync(aceCollection.Aces, entry, notify, aceCollection.Message, aceCollection.AdvancedSettings);
- warning ??= warningMessage;
-
- if (changed)
- {
- foreach (var e in eventTypes)
- {
- var user = e.User ?? await _userManager.GetUserByEmailAsync(e.Email);
- var name = user.DisplayUserName(false, _displayUserSettingsHelper);
-
- var access = e.Access;
-
- if (entry.FileEntryType == FileEntryType.Folder && DocSpaceHelper.IsRoom(((Folder)entry).FolderType))
- {
- switch (e.EventType)
- {
- case EventType.Create:
- _ = _filesMessageService.SendAsync(MessageAction.RoomCreateUser, entry, user.Id, name, GetAccessString(access));
- break;
- case EventType.Remove:
- _ = _filesMessageService.SendAsync(MessageAction.RoomRemoveUser, entry, user.Id, name, GetAccessString(access));
- break;
- case EventType.Update:
- _ = _filesMessageService.SendAsync(MessageAction.RoomUpdateAccessForUser, entry, user.Id, access, name);
- break;
- }
- }
- else
- {
-
- _ = _filesMessageService.SendAsync(
- entry.FileEntryType == FileEntryType.Folder ? MessageAction.FolderUpdatedAccessFor : MessageAction.FileUpdatedAccessFor,
- entry,
- entry.Title, name, GetAccessString(access));
- }
+ _ = _filesMessageService.SendAsync(
+ entry.FileEntryType == FileEntryType.Folder ? MessageAction.FolderUpdatedAccessFor : MessageAction.FileUpdatedAccessFor,
+ entry,
+ entry.Title, name, GetAccessString(ace.Access));
}
}
}
@@ -2666,7 +2668,7 @@ public class FileStorageService //: IFileStorageService
}
}
- public async Task> SetInvitationLinkAsync(T roomId, Guid linkId, string title, FileShare share)
+ public async Task SetInvitationLinkAsync(T roomId, Guid linkId, string title, FileShare share)
{
var expirationDate = DateTime.UtcNow.Add(_invitationLinkHelper.IndividualLinkExpirationInterval);
@@ -2675,13 +2677,13 @@ public class FileStorageService //: IFileStorageService
return await SetAceLinkAsync(room, SubjectType.InvitationLink, linkId, title, share, _actions[SubjectType.InvitationLink], expirationDate);
}
- public async Task> SetExternalLinkAsync(T entryId, FileEntryType entryType, Guid linkId, string title, FileShare share, DateTime expirationDate = default,
+ public async Task SetExternalLinkAsync(T entryId, FileEntryType entryType, Guid linkId, string title, FileShare share, DateTime expirationDate = default,
string password = null, bool disabled = false, bool denyDownload = false)
{
FileEntry entry = entryType == FileEntryType.File ? (await GetFileDao().GetFileAsync(entryId)).NotFoundIfNull()
: (await GetFolderDao().GetFolderAsync(entryId)).NotFoundIfNull();
- return await SetAceLinkAsync(entry, SubjectType.ExternalLink, linkId, title, share, _actions[SubjectType.ExternalLink], expirationDate, password, disabled, denyDownload, 10);
+ return await SetAceLinkAsync(entry, SubjectType.ExternalLink, linkId, title, share, _actions[SubjectType.ExternalLink], expirationDate, password, disabled, denyDownload);
}
public async Task SetAceLinkAsync(T fileId, FileShare share)
@@ -2701,8 +2703,8 @@ public class FileStorageService //: IFileStorageService
try
{
- var (changed, _) = await _fileSharingAceHelper.SetAceObjectAsync(aces, file, false, null, null);
- if (changed)
+ var result = await _fileSharingAceHelper.SetAceObjectAsync(aces, file, false, null, null);
+ if (result.Changed)
{
_ = _filesMessageService.SendAsync(MessageAction.FileExternalLinkAccessUpdated, file, file.Title, GetAccessString(share));
}
@@ -3119,10 +3121,13 @@ public class FileStorageService //: IFileStorageService
public async Task KeepNewFileNameAsync(bool set)
{
- _filesSettingsHelper.KeepNewFileName = set;
- await _messageService.SendHeadersMessageAsync(MessageAction.DocumentsKeepNewFileNameSettingsUpdated);
-
- return _filesSettingsHelper.KeepNewFileName;
+ var current = _filesSettingsHelper.KeepNewFileName;
+ if (current != set)
+ {
+ _filesSettingsHelper.KeepNewFileName = set;
+ await _messageService.SendHeadersMessageAsync(MessageAction.DocumentsKeepNewFileNameSettingsUpdated);
+ }
+ return set;
}
public bool HideConfirmConvert(bool isForSave)
@@ -3262,36 +3267,62 @@ public class FileStorageService //: IFileStorageService
return fileIds;
}
- public async Task ResendEmailInvitationsAsync(T id, IEnumerable usersIds)
+ public async Task ResendEmailInvitationsAsync(T id, IEnumerable usersIds, bool resendAll)
{
- ArgumentNullException.ThrowIfNull(usersIds);
+ if (!resendAll && (usersIds == null || !usersIds.Any()))
+ {
+ return;
+ }
var folderDao = _daoFactory.GetFolderDao();
- var room = await folderDao.GetFolderAsync(id);
+ var room = await folderDao.GetFolderAsync(id).NotFoundIfNull();
- ErrorIf(room == null, FilesCommonResource.ErrorMassage_FolderNotFound);
ErrorIf(!await _fileSecurity.CanEditRoomAsync(room), FilesCommonResource.ErrorMassage_SecurityException);
- var shares = (await _fileSharing.GetSharedInfoAsync(room)).ToDictionary(k => k.Id, v => v);
-
- foreach (var userId in usersIds)
+ if (!resendAll)
{
- if (!shares.TryGetValue(userId, out var share))
+ await foreach (var ace in _fileSharing.GetPureSharesAsync(room, usersIds))
{
- continue;
+ var user = await _userManager.GetUsersAsync(ace.Id);
+
+ var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, ace.Access, _authContext.CurrentAccount.ID, room.Id.ToString());
+ await _studioNotifyService.SendEmailRoomInviteAsync(user.Email, room.Title, link);
+ }
+
+ return;
+ }
+
+ const int margin = 1;
+ const int packSize = 1000;
+ var offset = 0;
+ var finish = false;
+
+ while (!finish)
+ {
+ var counter = 0;
+
+ await foreach (var ace in _fileSharing.GetRoomSharesAsync(room, ShareFilterType.User, EmployeeActivationStatus.Pending, offset, packSize + margin))
+ {
+ counter++;
+
+ if (counter > packSize)
+ {
+ offset += packSize;
+ break;
+ }
+
+ var user = await _userManager.GetUsersAsync(ace.Id);
+
+ var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, ace.Access, _authContext.CurrentAccount.ID, id.ToString());
+ var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
+
+ await _studioNotifyService.SendEmailRoomInviteAsync(user.Email, room.Title, shortenLink);
}
- var user = await _userManager.GetUserAsync(share.Id, null);
-
- if (user.ActivationStatus != EmployeeActivationStatus.Pending)
+ if (counter <= packSize)
{
- continue;
+ finish = true;
}
-
- var link = await _invitationLinkService.GetInvitationLinkAsync(user.Email, share.Access, _authContext.CurrentAccount.ID, id.ToString());
- var shortenLink = await _urlShortener.GetShortenLinkAsync(link);
-
- await _studioNotifyService.SendEmailRoomInviteAsync(user.Email, room.Title, shortenLink);
}
}
@@ -3435,9 +3466,8 @@ public class FileStorageService //: IFileStorageService
}
}
- private async Task> SetAceLinkAsync(FileEntry entry, SubjectType subjectType, Guid linkId, string title, FileShare share,
- IReadOnlyDictionary messageActions, DateTime expirationDate = default, string password = null, bool disabled = false, bool denyDownload = false,
- int maxLinksCount = int.MaxValue)
+ private async Task SetAceLinkAsync(FileEntry entry, SubjectType subjectType, Guid linkId, string title, FileShare share,
+ IReadOnlyDictionary messageActions, DateTime expirationDate = default, string password = null, bool disabled = false, bool denyDownload = false)
{
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(title);
@@ -3446,25 +3476,6 @@ public class FileStorageService //: IFileStorageService
linkId = Guid.NewGuid();
}
- var action = EventType.Create;
-
- var links = (await _fileSecurity.GetSharesAsync(entry))
- .Where(r => r.SubjectType == subjectType).ToList();
-
- if (share == FileShare.None)
- {
- action = EventType.Remove;
- }
- else if (links.Any(r => r.Subject == linkId))
- {
- action = EventType.Update;
- }
-
- if (action == EventType.Create && links.Count == maxLinksCount)
- {
- throw GenerateException(new InvalidOperationException(FilesCommonResource.ErrorMessage_MaxLinksCount));
- }
-
var options = new FileShareOptions
{
Title = title,
@@ -3497,11 +3508,16 @@ public class FileStorageService //: IFileStorageService
try
{
- var (changed, _) = await _fileSharingAceHelper.SetAceObjectAsync(aces, entry, false, null, null);
+ var result = await _fileSharingAceHelper.SetAceObjectAsync(aces, entry, false, null, null);
- if (changed)
+ if (!string.IsNullOrEmpty(result.Warning))
{
- _ = _filesMessageService.SendAsync(messageActions[action], entry, entry.Title, GetAccessString(share));
+ throw GenerateException(new InvalidOperationException(result.Warning));
+ }
+
+ if (result.Changed)
+ {
+ _ = _filesMessageService.SendAsync(messageActions[result.HandledAces[0].Event], entry, entry.Title, GetAccessString(share));
}
}
catch (Exception e)
@@ -3509,9 +3525,7 @@ public class FileStorageService //: IFileStorageService
throw GenerateException(e);
}
- return entry.FileEntryType == FileEntryType.File ?
- await GetSharedInfoAsync(new[] { entry.Id }, Array.Empty()) :
- await GetSharedInfoAsync(Array.Empty(), new[] { entry.Id });
+ return (await _fileSharing.GetPureSharesAsync(entry, new[] { linkId }).FirstOrDefaultAsync());
}
private async Task> GetFullAceWrappersAsync(IEnumerable share)
@@ -3569,13 +3583,6 @@ public class FileStorageService //: IFileStorageService
await SetAceObjectAsync(aceCollection, notify);
}
- private enum EventType
- {
- Update,
- Create,
- Remove
- }
-
private static readonly IReadOnlyDictionary> _actions =
new Dictionary>
{
diff --git a/products/ASC.Files/Core/Core/Security/FileSecurity.cs b/products/ASC.Files/Core/Core/Security/FileSecurity.cs
index efcfee73ad..7d19ac4f40 100644
--- a/products/ASC.Files/Core/Core/Security/FileSecurity.cs
+++ b/products/ASC.Files/Core/Core/Security/FileSecurity.cs
@@ -926,8 +926,9 @@ public class FileSecurity : IFileSecurity
FileShareRecord ace;
- if (!isRoom && e.RootFolderType is FolderType.VirtualRooms or FolderType.Archive &&
- _cachedRecords.TryGetValue(GetCacheKey(e.ParentId, userId), out var value))
+ if (!isRoom && e.RootFolderType is FolderType.VirtualRooms or FolderType.Archive &&
+ (_cachedRecords.TryGetValue(GetCacheKey(e.ParentId, userId), out var value)) ||
+ _cachedRecords.TryGetValue(GetCacheKey(e.ParentId, await _externalShare.GetLinkIdAsync()), out value))
{
ace = value.Clone();
ace.EntryId = e.Id;
@@ -965,6 +966,14 @@ public class FileSecurity : IFileSecurity
.ThenByDescending(r => r.Share, new FileShareRecord.ShareComparer())
.FirstOrDefault();
}
+
+ if (!isRoom && e.RootFolderType is FolderType.VirtualRooms or FolderType.Archive &&
+ ace is { SubjectType: SubjectType.User or SubjectType.ExternalLink })
+ {
+ var id = ace.SubjectType == SubjectType.ExternalLink ? ace.Subject : userId;
+
+ _cachedRecords.TryAdd(GetCacheKey(e.ParentId, id), ace);
+ }
}
if (ace is { SubjectType: SubjectType.ExternalLink } && ace.Subject != userId &&
@@ -984,11 +993,6 @@ public class FileSecurity : IFileSecurity
e.Access = ace?.Share ?? defaultShare;
e.Access = e.RootFolderType is FolderType.ThirdpartyBackup ? FileShare.Restrict : e.Access;
- if (ace is { IsLink: false } && !isRoom && e.RootFolderType is FolderType.VirtualRooms or FolderType.Archive && e.Access != FileShare.None)
- {
- _cachedRecords.TryAdd(GetCacheKey(e.ParentId, userId), ace);
- }
-
switch (action)
{
case FilesSecurityActions.Read:
@@ -996,7 +1000,8 @@ public class FileSecurity : IFileSecurity
case FilesSecurityActions.Mute:
return e.Access != FileShare.Restrict;
case FilesSecurityActions.Comment:
- if (e.Access is FileShare.Comment or FileShare.Review ||
+ if (e.Access is FileShare.Comment ||
+ e.Access == FileShare.Review ||
e.Access == FileShare.CustomFilter ||
e.Access == FileShare.ReadWrite ||
e.Access == FileShare.RoomAdmin ||
@@ -1149,7 +1154,7 @@ public class FileSecurity : IFileSecurity
if (e.Access != FileShare.Restrict && ace?.Options is not { DenyDownload: true })
{
return true;
- }
+ }
break;
}
@@ -1193,6 +1198,33 @@ public class FileSecurity : IFileSecurity
return await _daoFactory.GetSecurityDao().GetSharesAsync(entry, subjects);
}
+ public IAsyncEnumerable GetPureSharesAsync(FileEntry entry, IEnumerable subjects)
+ {
+ return _daoFactory.GetSecurityDao().GetPureSharesAsync(entry, subjects);
+ }
+
+ public IAsyncEnumerable GetPureSharesAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status, int offset = 0, int count = -1)
+ {
+ return _daoFactory.GetSecurityDao().GetPureSharesAsync(entry, filterType, status, offset, count);
+ }
+
+ public Task GetPureSharesCountAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status)
+ {
+ return _daoFactory.GetSecurityDao().GetPureSharesCountAsync(entry, filterType, status);
+ }
+
+ public IAsyncEnumerable GetUsersWithSharedAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus,
+ bool excludeShared, int offset, int count)
+ {
+ return _daoFactory.GetSecurityDao().GetUsersWithSharedAsync(entry, text, employeeStatus, activationStatus, excludeShared, offset, count);
+ }
+
+ public async Task GetUsersWithSharedCountAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus,
+ bool excludeShared)
+ {
+ return await _daoFactory.GetSecurityDao().GetUsersWithSharedCountAsync(entry, text, employeeStatus, activationStatus, excludeShared);
+ }
+
public async IAsyncEnumerable GetSharesForMeAsync(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false)
{
var securityDao = _daoFactory.GetSecurityDao();
diff --git a/products/ASC.Files/Core/Core/Security/FileShareRecord.cs b/products/ASC.Files/Core/Core/Security/FileShareRecord.cs
index 2eda6b582c..acbea42e6d 100644
--- a/products/ASC.Files/Core/Core/Security/FileShareRecord.cs
+++ b/products/ASC.Files/Core/Core/Security/FileShareRecord.cs
@@ -41,17 +41,23 @@ public class FileShareRecord
public class ShareComparer : IComparer
{
- private static readonly int[] _shareOrder = new[]
+ private static readonly int[] _shareOrder =
{
- (int)FileShare.None,
- (int)FileShare.ReadWrite,
- (int)FileShare.CustomFilter,
- (int)FileShare.Review,
- (int)FileShare.FillForms,
- (int)FileShare.Comment,
- (int)FileShare.Read,
- (int)FileShare.Restrict,
- (int)FileShare.Varies
+ (int)FileShare.None,
+ (int)FileShare.RoomAdmin,
+ (int)FileShare.Collaborator,
+ (int)FileShare.Editing,
+ (int)FileShare.FillForms,
+ (int)FileShare.Review,
+ (int)FileShare.Comment,
+ (int)FileShare.Read,
+
+ // Not used
+
+ (int)FileShare.ReadWrite,
+ (int)FileShare.CustomFilter,
+ (int)FileShare.Varies,
+ (int)FileShare.Restrict
};
public int Compare(FileShare x, FileShare y)
@@ -70,3 +76,39 @@ public class SmallShareRecord
public FileShare Share { get; set; }
public SubjectType SubjectType { get; set; }
}
+
+
+public static class ShareCompareHelper
+{
+ private static readonly ConcurrentDictionary _predicates = new();
+
+ public static Expression> GetCompareExpression(Expression> memberExpression)
+ {
+ var type = typeof(TType);
+ var key = type.ToString();
+
+ if (_predicates.TryGetValue(key, out var value))
+ {
+ return (Expression>)value;
+ }
+
+ var shares = Enum.GetValues()
+ .Order(new FileShareRecord.ShareComparer())
+ .ToList();
+
+ ConditionalExpression expression = null;
+
+ for (var i = shares.Count - 1; i >= 0; i--)
+ {
+ expression = Expression.Condition(
+ Expression.Equal(memberExpression.Body, Expression.Constant(shares[i])), Expression.Constant(i),
+ expression != null ? expression : Expression.Constant(i + 1));
+ }
+
+ var predicate = Expression.Lambda>(expression!, memberExpression.Parameters[0]);
+
+ _predicates.TryAdd(key, predicate);
+
+ return predicate;
+ }
+}
\ No newline at end of file
diff --git a/products/ASC.Files/Core/Core/Security/ISecurityDao.cs b/products/ASC.Files/Core/Core/Security/ISecurityDao.cs
index b733854431..1165cae914 100644
--- a/products/ASC.Files/Core/Core/Security/ISecurityDao.cs
+++ b/products/ASC.Files/Core/Core/Security/ISecurityDao.cs
@@ -38,4 +38,9 @@ public interface ISecurityDao
IAsyncEnumerable GetPureShareRecordsAsync(FileEntry entry);
Task DeleteShareRecordsAsync(IEnumerable records);
Task IsSharedAsync(T entryId, FileEntryType type);
+ IAsyncEnumerable GetPureSharesAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status, int offset = 0, int count = -1);
+ Task GetPureSharesCountAsync(FileEntry entry, ShareFilterType filterType, EmployeeActivationStatus? status);
+ IAsyncEnumerable GetPureSharesAsync(FileEntry entry, IEnumerable subjects);
+ IAsyncEnumerable GetUsersWithSharedAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus, bool excludeShared, int offset = 0, int count = -1);
+ Task GetUsersWithSharedCountAsync(FileEntry entry, string text, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus, bool excludeShared);
}
diff --git a/products/ASC.Files/Core/Core/Security/SubjectType.cs b/products/ASC.Files/Core/Core/Security/SubjectType.cs
index 9d03a46f72..043da2cc7c 100644
--- a/products/ASC.Files/Core/Core/Security/SubjectType.cs
+++ b/products/ASC.Files/Core/Core/Security/SubjectType.cs
@@ -26,6 +26,15 @@
namespace ASC.Files.Core.Security;
+[Flags]
+public enum ShareFilterType
+{
+ User = 0,
+ InvitationLink = 1,
+ ExternalLink = 2,
+ Link = InvitationLink | ExternalLink
+}
+
public enum SubjectType
{
User = 0,
diff --git a/products/ASC.Files/Core/Core/UsersInRoomFeature.cs b/products/ASC.Files/Core/Core/UsersInRoomFeature.cs
index 625dc1dddd..4bd1f91da2 100644
--- a/products/ASC.Files/Core/Core/UsersInRoomFeature.cs
+++ b/products/ASC.Files/Core/Core/UsersInRoomFeature.cs
@@ -65,6 +65,6 @@ public class UsersInRoomStatistic : ITenantQuotaFeatureStat !r.IsLink).CountAsync();
+ return await securityDao.GetPureSharesCountAsync(folder, ShareFilterType.User, null);
}
}
\ No newline at end of file
diff --git a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDownloadOperation.cs
index 981bfcbec9..ecb5e081a2 100644
--- a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDownloadOperation.cs
+++ b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDownloadOperation.cs
@@ -217,7 +217,7 @@ class FileDownloadOperation : FileOperation, T>
PublishChanges();
- var filesMessageService = _serviceProvider.GetRequiredService();
+ var filesMessageService = scope.ServiceProvider.GetRequiredService();
foreach (var file in filesForSend)
{
var key = file.Id;
diff --git a/products/ASC.Files/Core/Services/WCFService/Wrappers/AceWrapper.cs b/products/ASC.Files/Core/Services/WCFService/Wrappers/AceWrapper.cs
index ce57a94fa7..774906cab3 100644
--- a/products/ASC.Files/Core/Services/WCFService/Wrappers/AceWrapper.cs
+++ b/products/ASC.Files/Core/Services/WCFService/Wrappers/AceWrapper.cs
@@ -42,7 +42,6 @@ public class AceWrapper : IMapFrom
public SubjectType SubjectType { get; set; }
public FileShareOptions FileShareOptions { get; set; }
public bool CanEditAccess { get; set; }
- public bool IsTemplate { get; set; }
[JsonPropertyName("title")]
public string SubjectName { get; set; }
diff --git a/products/ASC.Files/Core/Utils/FileSharing.cs b/products/ASC.Files/Core/Utils/FileSharing.cs
index ac82ebf6ca..c47b1770cb 100644
--- a/products/ASC.Files/Core/Utils/FileSharing.cs
+++ b/products/ASC.Files/Core/Utils/FileSharing.cs
@@ -47,6 +47,9 @@ public class FileSharingAceHelper
private readonly UserManagerWrapper _userManagerWrapper;
private readonly CountPaidUserChecker _countPaidUserChecker;
private readonly IUrlShortener _urlShortener;
+
+ private const int MaxInvitationLinks = 1;
+ private const int MaxExternalLinks = 10;
public FileSharingAceHelper(
FileSecurity fileSecurity,
@@ -86,23 +89,20 @@ public class FileSharingAceHelper
_urlShortener = urlShortener;
}
- public async Task<(bool, string)> SetAceObjectAsync(List aceWrappers, FileEntry entry, bool notify, string message, AceAdvancedSettingsWrapper advancedSettings)
+ public async Task SetAceObjectAsync(List aceWrappers, FileEntry entry, bool notify, string message, AceAdvancedSettingsWrapper advancedSettings)
{
if (entry == null)
{
throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest);
}
- if (!aceWrappers.All(r => r.Id == _authContext.CurrentAccount.ID && r.Access == FileShare.None) && !await _fileSharingHelper.CanSetAccessAsync(entry) && advancedSettings is not { InvitationLink: true })
- {
- throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);
- }
-
- if (entry is Folder { Private: true } && advancedSettings is not { AllowSharingPrivateRoom: true })
+ if (!aceWrappers.All(r => r.Id == _authContext.CurrentAccount.ID && r.Access == FileShare.None) &&
+ !await _fileSharingHelper.CanSetAccessAsync(entry) && advancedSettings is not { InvitationLink: true })
{
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);
}
+ var handledAces = new List<(EventType, AceWrapper)>(aceWrappers.Count);
var ownerId = entry.RootFolderType == FolderType.USER ? entry.RootCreateBy : entry.CreateBy;
var room = entry is Folder folder && DocSpaceHelper.IsRoom(folder.FolderType) ? folder : null;
var entryType = entry.FileEntryType;
@@ -110,16 +110,23 @@ public class FileSharingAceHelper
var usersWithoutRight = new List();
var changed = false;
string warning = null;
- var shares = (await _fileSecurity.GetSharesAsync(entry)).ToList();
+ var shares = await _fileSecurity.GetPureSharesAsync(entry, aceWrappers.Select(a => a.Id))
+ .ToDictionaryAsync(r => r.Subject);
foreach (var w in aceWrappers.OrderByDescending(ace => ace.SubjectGroup))
{
+ if (w.Id == _authContext.CurrentAccount.ID)
+ {
+ continue;
+ }
+
var emailInvite = !string.IsNullOrEmpty(w.Email);
var currentUserType = await _userManager.GetUserTypeAsync(w.Id);
var userType = EmployeeType.User;
- var existedShare = shares.FirstOrDefault(r => r.Subject == w.Id);
+ var existedShare = shares.Get(w.Id);
var rightIsAvailable = FileSecurity.AvailableUserRights.TryGetValue(currentUserType, out var userAccesses)
&& userAccesses.Contains(w.Access);
+ var eventType = existedShare != null ? w.Access == FileShare.None ? EventType.Remove : EventType.Update : EventType.Create;
if (room != null)
{
@@ -127,15 +134,44 @@ public class FileSharingAceHelper
{
continue;
}
-
- if (room.FolderType is not (FolderType.PublicRoom or FolderType.CustomRoom) && w.SubjectType == SubjectType.ExternalLink)
+
+ if (room.FolderType == FolderType.PublicRoom && w.Access == FileShare.Read && w.SubjectType != SubjectType.ExternalLink)
{
continue;
}
- if (room.FolderType == FolderType.PublicRoom && w.Access == FileShare.Read && w.SubjectType != SubjectType.ExternalLink)
+ switch (w.SubjectType)
{
- continue;
+ case SubjectType.ExternalLink when room.FolderType is not (FolderType.PublicRoom or FolderType.CustomRoom):
+ case SubjectType.ExternalLink when w.Access is not (FileShare.Read or FileShare.None):
+ continue;
+ case SubjectType.ExternalLink:
+ {
+ if (eventType == EventType.Create)
+ {
+ var linksCount = await _fileSecurity.GetPureSharesCountAsync(entry, ShareFilterType.ExternalLink, null);
+
+ if (linksCount >= MaxExternalLinks)
+ {
+ warning ??= string.Format(FilesCommonResource.ErrorMessage_MaxLinksCount, MaxExternalLinks);
+ continue;
+ }
+ }
+
+ break;
+ }
+ case SubjectType.InvitationLink when eventType == EventType.Create:
+ {
+ var linksCount = await _fileSecurity.GetPureSharesCountAsync(entry, ShareFilterType.InvitationLink, null);
+
+ if (linksCount >= MaxInvitationLinks)
+ {
+ warning ??= string.Format(FilesCommonResource.ErrorMessage_MaxLinksCount, MaxInvitationLinks);
+ continue;
+ }
+
+ break;
+ }
}
}
@@ -225,6 +261,7 @@ public class FileSharingAceHelper
await _fileSecurity.ShareAsync(entry.Id, entryType, w.Id, share, w.SubjectType, w.FileShareOptions);
changed = true;
+ handledAces.Add((eventType, w));
if (emailInvite)
{
@@ -271,9 +308,7 @@ public class FileSharingAceHelper
|| (share == FileShare.None && entry.RootFolderType == FolderType.COMMON);
var removeNew = share == FileShare.Restrict || (share == FileShare.None
- && (entry.RootFolderType == FolderType.USER ||
- entry.RootFolderType == FolderType.VirtualRooms ||
- entry.RootFolderType == FolderType.Archive));
+ && entry.RootFolderType is FolderType.USER or FolderType.VirtualRooms or FolderType.Archive);
listUsersId.ForEach(id =>
{
@@ -303,8 +338,7 @@ public class FileSharingAceHelper
await _fileMarker.MarkAsNewAsync(entry, recipients.Keys.ToList());
}
- if ((entry.RootFolderType == FolderType.USER
- || entry.RootFolderType == FolderType.Privacy)
+ if (entry.RootFolderType is FolderType.USER or FolderType.Privacy
&& notify)
{
await _notifyClient.SendShareNoticeAsync(entry, recipients, message);
@@ -322,7 +356,7 @@ public class FileSharingAceHelper
await _fileMarker.RemoveMarkAsNewAsync(entry, userId);
}
- return (changed, warning);
+ return new AceProcessingResult(changed, warning, handledAces);
}
public async Task RemoveAceAsync(FileEntry entry)
@@ -473,7 +507,72 @@ public class FileSharing
return await _fileSharingHelper.CanSetAccessAsync(entry);
}
- public async Task> GetSharedInfoAsync(FileEntry entry, IEnumerable subjectsTypes = null, bool withoutTemplates = false)
+ public async IAsyncEnumerable GetPureSharesAsync(FileEntry entry, IEnumerable subjects)
+ {
+ if (entry == null)
+ {
+ throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest);
+ }
+
+ if (!await _fileSecurity.CanReadAsync(entry))
+ {
+ _logger.ErrorUserCanTGetSharedInfo(_authContext.CurrentAccount.ID, entry.FileEntryType, entry.Id.ToString()!);
+
+ yield break;
+ }
+
+ var canEditAccess = await _fileSecurity.CanEditAccessAsync(entry);
+
+ await foreach (var record in _fileSecurity.GetPureSharesAsync(entry, subjects))
+ {
+ yield return await ToAceAsync(entry, record, canEditAccess);
+ }
+ }
+
+ public async IAsyncEnumerable GetRoomSharesAsync(Folder room, ShareFilterType filterType, EmployeeActivationStatus? status, int offset, int count)
+ {
+ if (room == null || !DocSpaceHelper.IsRoom(room.FolderType))
+ {
+ throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest);
+ }
+
+ if (!await _fileSecurity.CanReadAsync(room))
+ {
+ _logger.ErrorUserCanTGetSharedInfo(_authContext.CurrentAccount.ID, room.FileEntryType, room.Id.ToString()!);
+
+ yield break;
+ }
+
+ var canEditAccess = await _fileSecurity.CanEditAccessAsync(room);
+
+ var allDefaultAces = await GetDefaultRoomAcesAsync(room, filterType, status).ToListAsync();
+ var defaultAces = allDefaultAces.Skip(offset).Take(count).ToList();
+
+ offset = Math.Max(defaultAces.Count > 0 ? 0 : offset - allDefaultAces.Count, 0);
+ count -= defaultAces.Count;
+
+ var records = _fileSecurity.GetPureSharesAsync(room, filterType, status, offset, count);
+
+ foreach (var record in defaultAces)
+ {
+ yield return record;
+ }
+
+ await foreach (var record in records)
+ {
+ yield return await ToAceAsync(room, record, canEditAccess);
+ }
+ }
+
+ public async Task GetRoomSharesCountAsync(Folder room, ShareFilterType filterType)
+ {
+ var defaultAces = await GetDefaultRoomAcesAsync(room, filterType, null).CountAsync();
+ var sharesCount = await _fileSecurity.GetPureSharesCountAsync(room, filterType, null);
+
+ return defaultAces + sharesCount;
+ }
+
+ public async Task> GetSharedInfoAsync(FileEntry entry, IEnumerable subjectsTypes = null)
{
if (entry == null)
{
@@ -586,38 +685,6 @@ public class FileSharing
result.Add(w);
}
- if (isRoom && canEditAccess && !withoutTemplates)
- {
- var invitationId = Guid.NewGuid();
-
- var invitationAceTemplate = new AceWrapper
- {
- Id = invitationId,
- Link = _invitationLinkService.GetInvitationLink(invitationId, _authContext.CurrentAccount.ID),
- SubjectGroup = true,
- Access = ((Folder)entry).FolderType == FolderType.PublicRoom ? FileShare.RoomAdmin : FileShare.Read,
- Owner = false,
- IsTemplate = true,
- SubjectType = SubjectType.InvitationLink
- };
-
- var externalId = Guid.NewGuid();
-
- var externalAceTemplate = new AceWrapper
- {
- Id = externalId,
- Link = await _externalShare.GetLinkAsync(externalId),
- SubjectGroup = true,
- Access = FileShare.Read,
- Owner = false,
- IsTemplate = true,
- SubjectType = SubjectType.ExternalLink
- };
-
- result.Add(invitationAceTemplate);
- result.Add(externalAceTemplate);
- }
-
if (entry.FileEntryType == FileEntryType.File && result.All(w => w.Id != FileConstant.ShareLinkId)
&& entry.FileEntryType == FileEntryType.File
&& !((File)entry).Encrypted)
@@ -696,8 +763,7 @@ public class FileSharing
return result;
}
- public async Task> GetSharedInfoAsync(IEnumerable fileIds, IEnumerable folderIds, IEnumerable subjectTypes = null,
- bool withoutTemplates = false)
+ public async Task> GetSharedInfoAsync(IEnumerable fileIds, IEnumerable folderIds, IEnumerable subjectTypes = null)
{
if (!_authContext.IsAuthenticated)
{
@@ -719,7 +785,7 @@ public class FileSharing
IEnumerable acesForObject;
try
{
- acesForObject = await GetSharedInfoAsync(entry, subjectTypes, withoutTemplates);
+ acesForObject = await GetSharedInfoAsync(entry, subjectTypes);
}
catch (Exception e)
{
@@ -821,4 +887,94 @@ public class FileSharing
.Where(aceWrapper => !aceWrapper.Id.Equals(FileConstant.ShareLinkId) || aceWrapper.Access != FileShare.Restrict)
.Select(aceWrapper => new AceShortWrapper(aceWrapper)));
}
+
+ private async IAsyncEnumerable GetDefaultRoomAcesAsync(Folder room, ShareFilterType filterType, EmployeeActivationStatus? status)
+ {
+ if (filterType != ShareFilterType.User)
+ {
+ yield break;
+ }
+
+ if (status.HasValue)
+ {
+ var user = await _userManager.GetUsersAsync(room.CreateBy);
+
+ if (user.ActivationStatus != status.Value)
+ {
+ yield break;
+ }
+ }
+
+ var owner = new AceWrapper
+ {
+ Id = room.CreateBy,
+ SubjectName = await _global.GetUserNameAsync(room.CreateBy),
+ SubjectGroup = false,
+ Access = FileShare.ReadWrite,
+ Owner = true,
+ CanEditAccess = false,
+ };
+
+ yield return owner;
+ }
+
+ private async Task ToAceAsync(FileEntry entry, FileShareRecord record, bool canEditAccess)
+ {
+ var w = new AceWrapper
+ {
+ Id = record.Subject,
+ SubjectGroup = false,
+ Access = record.Share,
+ FileShareOptions = record.Options,
+ SubjectType = record.SubjectType
+ };
+
+ w.CanEditAccess = _authContext.CurrentAccount.ID != w.Id && (w.SubjectType is SubjectType.User or SubjectType.Group) && canEditAccess;
+
+ if (record.IsLink)
+ {
+ var link = record.SubjectType == SubjectType.InvitationLink ?
+ _invitationLinkService.GetInvitationLink(record.Subject, _authContext.CurrentAccount.ID) :
+ await _externalShare.GetLinkAsync(record.Subject);
+
+ w.Link = await _urlShortener.GetShortenLinkAsync(link);
+ w.SubjectGroup = true;
+ w.CanEditAccess = false;
+ w.FileShareOptions.Password = await _externalShare.GetPasswordAsync(w.FileShareOptions.Password);
+ w.SubjectType = record.SubjectType;
+ }
+ else
+ {
+ var user = await _userManager.GetUsersAsync(record.Subject);
+
+ w.SubjectName = user.DisplayUserName(false, _displayUserSettingsHelper);
+ w.Owner = entry.RootFolderType == FolderType.USER
+ ? entry.RootCreateBy == record.Subject
+ : entry.CreateBy == record.Subject;
+ w.LockedRights = record.Subject == _authContext.CurrentAccount.ID;
+ }
+
+ return w;
+ }
+}
+
+public class AceProcessingResult
+{
+ public bool Changed { get; }
+ public string Warning { get; }
+ public IReadOnlyList<(EventType Event, AceWrapper Ace)> HandledAces { get; }
+
+ public AceProcessingResult(bool changed, string warning, IReadOnlyList<(EventType Event, AceWrapper Ace)> handledAces)
+ {
+ Changed = changed;
+ Warning = warning;
+ HandledAces = handledAces;
+ }
+}
+
+public enum EventType
+{
+ Update,
+ Create,
+ Remove
}
\ No newline at end of file
diff --git a/products/ASC.Files/Server/Api/VirtualRoomsController.cs b/products/ASC.Files/Server/Api/VirtualRoomsController.cs
index f029ae6200..b92052cb9b 100644
--- a/products/ASC.Files/Server/Api/VirtualRoomsController.cs
+++ b/products/ASC.Files/Server/Api/VirtualRoomsController.cs
@@ -1,4 +1,4 @@
-// (c) Copyright Ascensio System SIA 2010-2022
+// (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
@@ -40,7 +40,8 @@ public class VirtualRoomsInternalController : VirtualRoomsController
FileDtoHelper fileDtoHelper,
FileShareDtoHelper fileShareDtoHelper,
IMapper mapper,
- SocketManager socketManager) : base(
+ SocketManager socketManager,
+ ApiContext apiContext) : base(
globalFolderHelper,
fileOperationDtoHelper,
coreBaseSettings,
@@ -51,7 +52,8 @@ public class VirtualRoomsInternalController : VirtualRoomsController
fileDtoHelper,
fileShareDtoHelper,
mapper,
- socketManager)
+ socketManager,
+ apiContext)
{
}
@@ -88,7 +90,8 @@ public class VirtualRoomsThirdPartyController : VirtualRoomsController
FileDtoHelper fileDtoHelper,
FileShareDtoHelper fileShareDtoHelper,
IMapper mapper,
- SocketManager socketManager) : base(
+ SocketManager socketManager,
+ ApiContext apiContext) : base(
globalFolderHelper,
fileOperationDtoHelper,
coreBaseSettings,
@@ -99,7 +102,8 @@ public class VirtualRoomsThirdPartyController : VirtualRoomsController
fileDtoHelper,
fileShareDtoHelper,
mapper,
- socketManager)
+ socketManager,
+ apiContext)
{
}
@@ -135,6 +139,7 @@ public abstract class VirtualRoomsController : ApiControllerBase
private readonly FileShareDtoHelper _fileShareDtoHelper;
private readonly IMapper _mapper;
private readonly SocketManager _socketManager;
+ private readonly ApiContext _apiContext;
protected VirtualRoomsController(
GlobalFolderHelper globalFolderHelper,
@@ -147,7 +152,8 @@ public abstract class VirtualRoomsController : ApiControllerBase
FileDtoHelper fileDtoHelper,
FileShareDtoHelper fileShareDtoHelper,
IMapper mapper,
- SocketManager socketManager) : base(folderDtoHelper, fileDtoHelper)
+ SocketManager socketManager,
+ ApiContext apiContext) : base(folderDtoHelper, fileDtoHelper)
{
_globalFolderHelper = globalFolderHelper;
_fileOperationDtoHelper = fileOperationDtoHelper;
@@ -158,6 +164,7 @@ public abstract class VirtualRoomsController : ApiControllerBase
_fileShareDtoHelper = fileShareDtoHelper;
_mapper = mapper;
_socketManager = socketManager;
+ _apiContext = apiContext;
}
///
@@ -286,22 +293,25 @@ public abstract class VirtualRoomsController : ApiControllerBase
var result = new RoomSecurityDto();
- if (inDto.Invitations != null && inDto.Invitations.Any())
+ if (inDto.Invitations == null || !inDto.Invitations.Any())
{
- var wrappers = _mapper.Map, List>(inDto.Invitations);
-
- var aceCollection = new AceCollection
- {
- Files = Array.Empty(),
- Folders = new[] { id },
- Aces = wrappers,
- Message = inDto.Message
- };
-
- result.Warning = await _fileStorageService.SetAceObjectAsync(aceCollection, inDto.Notify);
+ return result;
}
- result.Members = await GetRoomSecurityInfoAsync(id).ToListAsync();
+ var wrappers = _mapper.Map, List>(inDto.Invitations);
+
+ var aceCollection = new AceCollection
+ {
+ Files = Array.Empty(),
+ Folders = new[] { id },
+ Aces = wrappers,
+ Message = inDto.Message
+ };
+
+ result.Warning = await _fileStorageService.SetAceObjectAsync(aceCollection, inDto.Notify);
+ result.Members = await _fileStorageService.GetSharedInfoAsync(id, inDto.Invitations.Select(s => s.Id))
+ .SelectAwait(async a => await _fileShareDtoHelper.Get(a))
+ .ToListAsync();
return result;
}
@@ -312,19 +322,30 @@ public abstract class VirtualRoomsController : ApiControllerBase
/// Get room access rights
/// Rooms
/// Room ID
+ ///
+ /// Share type filter
+ ///
/// Security information of room files
/// api/2.0/files/rooms/{id}/share
/// GET
/// list
[HttpGet("rooms/{id}/share")]
- public async IAsyncEnumerable GetRoomSecurityInfoAsync(T id)
+ public async IAsyncEnumerable GetRoomSecurityInfoAsync(T id, ShareFilterType filterType = ShareFilterType.User)
{
- var fileShares = await _fileStorageService.GetSharedInfoAsync(Array.Empty(), new[] { id });
+ var offset = Convert.ToInt32(_apiContext.StartIndex);
+ var count = Convert.ToInt32(_apiContext.Count);
+ var counter = 0;
- foreach (var fileShareDto in fileShares)
+ var totalCountTask = _fileStorageService.GetRoomSharesCountAsync(id, filterType);
+
+ await foreach (var ace in _fileStorageService.GetRoomSharedInfoAsync(id, filterType, offset, count))
{
- yield return await _fileShareDtoHelper.Get(fileShareDto);
+ counter++;
+
+ yield return await _fileShareDtoHelper.Get(ace);
}
+
+ _apiContext.SetCount(counter).SetTotalCount(await totalCountTask);
}
///
@@ -339,9 +360,9 @@ public abstract class VirtualRoomsController : ApiControllerBase
/// PUT
/// list
[HttpPut("rooms/{id}/links")]
- public async IAsyncEnumerable SetLinkAsync(T id, LinkRequestDto inDto)
+ public async Task SetLinkAsync(T id, LinkRequestDto inDto)
{
- var fileShares = inDto.LinkType switch
+ var linkAce = inDto.LinkType switch
{
LinkType.Invitation => await _fileStorageService.SetInvitationLinkAsync(id, inDto.LinkId, inDto.Title, inDto.Access),
LinkType.External => await _fileStorageService.SetExternalLinkAsync(id, FileEntryType.Folder, inDto.LinkId, inDto.Title,
@@ -349,10 +370,7 @@ public abstract class VirtualRoomsController : ApiControllerBase
_ => throw new InvalidOperationException()
};
- foreach (var fileShareDto in fileShares)
- {
- yield return await _fileShareDtoHelper.Get(fileShareDto);
- }
+ return linkAce != null ? await _fileShareDtoHelper.Get(linkAce) : null;
}
///
@@ -369,21 +387,24 @@ public abstract class VirtualRoomsController : ApiControllerBase
[HttpGet("rooms/{id}/links")]
public async IAsyncEnumerable GetLinksAsync(T id, LinkType? type)
{
- var subjectTypes = type.HasValue
- ? type.Value switch
+ var filterType = type.HasValue ? type.Value switch
{
- LinkType.Invitation => new[] { SubjectType.InvitationLink },
- LinkType.External => new[] { SubjectType.ExternalLink },
- _ => new[] { SubjectType.InvitationLink, SubjectType.ExternalLink }
- }
- : new[] { SubjectType.InvitationLink, SubjectType.ExternalLink };
+ LinkType.Invitation => ShareFilterType.InvitationLink,
+ LinkType.External => ShareFilterType.ExternalLink,
+ _ => ShareFilterType.Link
+ }
+ : ShareFilterType.Link;
- var fileShares = await _fileStorageService.GetSharedInfoAsync(Array.Empty(), new[] { id }, subjectTypes, true);
-
- foreach (var fileShareDto in fileShares)
+ var counter = 0;
+
+ await foreach (var ace in _fileStorageService.GetRoomSharedInfoAsync(id, filterType, 0, 100))
{
- yield return await _fileShareDtoHelper.Get(fileShareDto);
+ counter++;
+
+ yield return await _fileShareDtoHelper.Get(ace);
}
+
+ _apiContext.SetCount(counter);
}
///
@@ -518,9 +539,9 @@ public abstract class VirtualRoomsController : ApiControllerBase
/// api/2.0/files/rooms/{id}/resend
/// POST
[HttpPost("rooms/{id}/resend")]
- public async Task ResendEmailInvitationsAsync(T id, UserInvintationRequestDto inDto)
+ public async Task ResendEmailInvitationsAsync(T id, UserInvitationRequestDto inDto)
{
- await _fileStorageService.ResendEmailInvitationsAsync(id, inDto.UsersIds);
+ await _fileStorageService.ResendEmailInvitationsAsync(id, inDto.UsersIds, inDto.ResendAll);
}
protected void ErrorIfNotDocSpace()
diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs
index 10e9235c06..131dd0b580 100644
--- a/products/ASC.People/Server/Api/UserController.cs
+++ b/products/ASC.People/Server/Api/UserController.cs
@@ -1889,3 +1889,72 @@ public class UserController : PeopleControllerBase
// }
//}
}
+
+[ConstraintRoute("int")]
+public class UserControllerAdditionalInternal : UserControllerAdditional
+{
+ public UserControllerAdditionalInternal(
+ EmployeeFullDtoHelper employeeFullDtoHelper,
+ FileSecurity fileSecurity,
+ ApiContext apiContext,
+ IDaoFactory daoFactory)
+ : base(employeeFullDtoHelper, fileSecurity, apiContext, daoFactory)
+ {
+
+ }
+}
+
+public class UserControllerAdditionalThirdParty : UserControllerAdditional
+{
+ public UserControllerAdditionalThirdParty(
+ EmployeeFullDtoHelper employeeFullDtoHelper,
+ FileSecurity fileSecurity,
+ ApiContext apiContext,
+ IDaoFactory daoFactory)
+ : base(employeeFullDtoHelper, fileSecurity, apiContext, daoFactory)
+ {
+
+ }
+}
+
+public class UserControllerAdditional : ApiControllerBase
+{
+ private readonly EmployeeFullDtoHelper _employeeFullDtoHelper;
+ private readonly FileSecurity _fileSecurity;
+ private readonly ApiContext _apiContext;
+ private readonly IDaoFactory _daoFactory;
+
+ public UserControllerAdditional(
+ EmployeeFullDtoHelper employeeFullDtoHelper,
+ FileSecurity fileSecurity,
+ ApiContext apiContext,
+ IDaoFactory daoFactory)
+ {
+ _employeeFullDtoHelper = employeeFullDtoHelper;
+ _fileSecurity = fileSecurity;
+ _apiContext = apiContext;
+ _daoFactory = daoFactory;
+ }
+
+ [HttpGet("room/{id}")]
+ public async IAsyncEnumerable GetUsersWithRoomSharedAsync(T id, EmployeeStatus? employeeStatus, EmployeeActivationStatus? activationStatus, bool? excludeShared)
+ {
+ var offset = Convert.ToInt32(_apiContext.StartIndex);
+ var count = Convert.ToInt32(_apiContext.Count);
+
+ var room = (await _daoFactory.GetFolderDao().GetFolderAsync(id)).NotFoundIfNull();
+ var totalCountTask = _fileSecurity.GetUsersWithSharedCountAsync(room, _apiContext.FilterValue, employeeStatus, activationStatus, excludeShared ?? false);
+
+ var counter = 0;
+
+ await foreach (var u in _fileSecurity.GetUsersWithSharedAsync(room, _apiContext.FilterValue, employeeStatus, activationStatus, excludeShared ?? false, offset,
+ count))
+ {
+ counter++;
+
+ yield return await _employeeFullDtoHelper.GetFullAsync(u.UserInfo, u.Shared);
+ }
+
+ _apiContext.SetCount(counter).SetTotalCount(await totalCountTask);
+ }
+}
\ No newline at end of file
diff --git a/products/ASC.People/Server/GlobalUsings.cs b/products/ASC.People/Server/GlobalUsings.cs
index 2898587e2e..6575d22724 100644
--- a/products/ASC.People/Server/GlobalUsings.cs
+++ b/products/ASC.People/Server/GlobalUsings.cs
@@ -24,23 +24,24 @@
// 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
-global using System.Globalization;
+global using System.Globalization;
global using System.Net.Mail;
global using System.Security;
-global using System.Security.Claims;
+global using System.Security.Claims;
global using System.ServiceModel.Security;
global using System.Web;
-
+
global using ASC.Api.Core;
global using ASC.Api.Core.Convention;
global using ASC.Api.Core.Extensions;
global using ASC.Api.Core.Model;
-global using ASC.Api.Core.Security;
+global using ASC.Api.Core.Security;
+global using ASC.Api.Core.Routing;
global using ASC.Api.Utils;
global using ASC.Common;
-global using ASC.Common.Caching;
+global using ASC.Common.Caching;
global using ASC.Common.Log;
-global using ASC.Common.Threading;
+global using ASC.Common.Threading;
global using ASC.Common.Utils;
global using ASC.Common.Web;
global using ASC.Core;
@@ -54,19 +55,19 @@ global using ASC.Data.Reassigns;
global using ASC.FederatedLogin;
global using ASC.FederatedLogin.LoginProviders;
global using ASC.FederatedLogin.Profile;
-global using ASC.Files.Core;
-global using ASC.Files.Core.Core;
-global using ASC.Files.Core.EF;
+global using ASC.Files.Core;
+global using ASC.Files.Core.Core;
+global using ASC.Files.Core.EF;
global using ASC.Files.Core.Resources;
global using ASC.Files.Core.Security;
-global using ASC.Files.Core.VirtualRooms;
+global using ASC.Files.Core.VirtualRooms;
global using ASC.MessagingSystem.Core;
global using ASC.MessagingSystem.EF.Model;
global using ASC.People;
global using ASC.People.Api;
global using ASC.People.ApiModels.RequestDto;
global using ASC.People.ApiModels.ResponseDto;
-global using ASC.People.Log;
+global using ASC.People.Log;
global using ASC.People.Resources;
global using ASC.Security.Cryptography;
global using ASC.Web.Api.Models;
@@ -74,30 +75,30 @@ global using ASC.Web.Api.Routing;
global using ASC.Web.Core;
global using ASC.Web.Core.Mobile;
global using ASC.Web.Core.PublicResources;
-global using ASC.Web.Core.Quota;
+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.Studio.Core;
global using ASC.Web.Studio.Core.Notify;
global using ASC.Web.Studio.Utility;
-
+
global using Autofac;
-
+
global using Microsoft.AspNetCore.Http.Extensions;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.RateLimiting;
-global using Microsoft.EntityFrameworkCore;
+global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Hosting.WindowsServices;
-
+
global using SixLabors.ImageSharp;
-global using SixLabors.ImageSharp.Formats;
-
+global using SixLabors.ImageSharp.Formats;
+
global using Module = ASC.Api.Core.Module;
-global using SecurityContext = ASC.Core.SecurityContext;
-global using AllowAnonymousAttribute = Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute;
-global using AuthorizeAttribute = Microsoft.AspNetCore.Authorization.AuthorizeAttribute;
-global using HttpDeleteAttribute = Microsoft.AspNetCore.Mvc.HttpDeleteAttribute;
-global using HttpGetAttribute = Microsoft.AspNetCore.Mvc.HttpGetAttribute;
-global using HttpPostAttribute = Microsoft.AspNetCore.Mvc.HttpPostAttribute;
+global using SecurityContext = ASC.Core.SecurityContext;
+global using AllowAnonymousAttribute = Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute;
+global using AuthorizeAttribute = Microsoft.AspNetCore.Authorization.AuthorizeAttribute;
+global using HttpDeleteAttribute = Microsoft.AspNetCore.Mvc.HttpDeleteAttribute;
+global using HttpGetAttribute = Microsoft.AspNetCore.Mvc.HttpGetAttribute;
+global using HttpPostAttribute = Microsoft.AspNetCore.Mvc.HttpPostAttribute;
global using HttpPutAttribute = Microsoft.AspNetCore.Mvc.HttpPutAttribute;
\ No newline at end of file
diff --git a/public/images/info.outline.react.svg b/public/images/info.outline.react.svg
index ac41fda0d9..38fb3cf6db 100644
--- a/public/images/info.outline.react.svg
+++ b/public/images/info.outline.react.svg
@@ -1,12 +1,10 @@
-
\ No newline at end of file
diff --git a/web/ASC.Web.Core/Users/UserPhotoManager.cs b/web/ASC.Web.Core/Users/UserPhotoManager.cs
index 4126a46126..5f14ee6ebb 100644
--- a/web/ASC.Web.Core/Users/UserPhotoManager.cs
+++ b/web/ASC.Web.Core/Users/UserPhotoManager.cs
@@ -164,19 +164,17 @@ public class UserPhotoManagerCache
public string SearchInCache(Guid userId, Size size)
{
- string fileName = null;
-
if (!_photofiles.TryGetValue(userId, out var val))
{
return null;
}
- if (!val.TryGetValue(UserPhotoManager.ToCache(size), out fileName))
+ if (!val.TryGetValue(UserPhotoManager.ToCache(size), out var fileName))
{
return null;
}
-
- if (String.IsNullOrEmpty(fileName))
+
+ if (string.IsNullOrEmpty(fileName))
{
fileName = val.Values.FirstOrDefault(x => !string.IsNullOrEmpty(x) && x.Contains("_orig_"));
}
diff --git a/yarn.lock b/yarn.lock
index 16876c82a7..e218ee00d1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -108,13 +108,13 @@ __metadata:
linkType: hard
"@aws-sdk/client-cloudwatch-logs@npm:^3.297.0":
- version: 3.418.0
- resolution: "@aws-sdk/client-cloudwatch-logs@npm:3.418.0"
+ version: 3.421.0
+ resolution: "@aws-sdk/client-cloudwatch-logs@npm:3.421.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
- "@aws-sdk/client-sts": 3.418.0
- "@aws-sdk/credential-provider-node": 3.418.0
+ "@aws-sdk/client-sts": 3.421.0
+ "@aws-sdk/credential-provider-node": 3.421.0
"@aws-sdk/middleware-host-header": 3.418.0
"@aws-sdk/middleware-logger": 3.418.0
"@aws-sdk/middleware-recursion-detection": 3.418.0
@@ -149,13 +149,13 @@ __metadata:
"@smithy/util-utf8": ^2.0.0
tslib: ^2.5.0
uuid: ^8.3.2
- checksum: cf250588753d42dbbd4605425aeb0a7a1838a0b46f0054f0f2e18c7075abfde3509d7ca9f25236a4188bff6e640da44d47d4236b8d479e209e5633c04ab55665
+ checksum: 8335143173c8c26e4c36af9ef323c42afe002acdeeade86b4ca2b0877e4382b0e18abdd66e9a8dcb2a5e308e450b0eb4002ef9d8f056cc612466337ae955b500
languageName: node
linkType: hard
-"@aws-sdk/client-sso@npm:3.418.0":
- version: 3.418.0
- resolution: "@aws-sdk/client-sso@npm:3.418.0"
+"@aws-sdk/client-sso@npm:3.421.0":
+ version: 3.421.0
+ resolution: "@aws-sdk/client-sso@npm:3.421.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
@@ -191,17 +191,17 @@ __metadata:
"@smithy/util-retry": ^2.0.2
"@smithy/util-utf8": ^2.0.0
tslib: ^2.5.0
- checksum: 54c17953ac1143f07fff8a462bddeb87a5cb10d5ffb269ed93e837da7b37d4d3ae81aa0986b23c0e687712c58320bb28b5ac0ab4a8cb2841fbb0ce2436df648d
+ checksum: 2dcfbd104668f49fc5b18af6a5bced3845e75c1facab7fd26e97c40ea447e9c29d4f3a5e14d90e66a008db251a6aa27fc8af7652e3c1d8916853ff37df28c72c
languageName: node
linkType: hard
-"@aws-sdk/client-sts@npm:3.418.0":
- version: 3.418.0
- resolution: "@aws-sdk/client-sts@npm:3.418.0"
+"@aws-sdk/client-sts@npm:3.421.0":
+ version: 3.421.0
+ resolution: "@aws-sdk/client-sts@npm:3.421.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
- "@aws-sdk/credential-provider-node": 3.418.0
+ "@aws-sdk/credential-provider-node": 3.421.0
"@aws-sdk/middleware-host-header": 3.418.0
"@aws-sdk/middleware-logger": 3.418.0
"@aws-sdk/middleware-recursion-detection": 3.418.0
@@ -237,7 +237,7 @@ __metadata:
"@smithy/util-utf8": ^2.0.0
fast-xml-parser: 4.2.5
tslib: ^2.5.0
- checksum: 594ce1a04a1c5aa6b21e7ddf0342d9705e27a60bfba3b30b192152987aba6bd6227d8e98e6ccddae1ccf7090de9e12737f8cd996918302ca574b69fe6f93ad37
+ checksum: c21a28288341a7f6749e61391846b7a6754de3594137a7c436b1d96d82a8043adc921b45f8d22e2894e50cdf3799f51143a42f214ae552bcd0e0088c85d2de09
languageName: node
linkType: hard
@@ -253,13 +253,13 @@ __metadata:
languageName: node
linkType: hard
-"@aws-sdk/credential-provider-ini@npm:3.418.0":
- version: 3.418.0
- resolution: "@aws-sdk/credential-provider-ini@npm:3.418.0"
+"@aws-sdk/credential-provider-ini@npm:3.421.0":
+ version: 3.421.0
+ resolution: "@aws-sdk/credential-provider-ini@npm:3.421.0"
dependencies:
"@aws-sdk/credential-provider-env": 3.418.0
"@aws-sdk/credential-provider-process": 3.418.0
- "@aws-sdk/credential-provider-sso": 3.418.0
+ "@aws-sdk/credential-provider-sso": 3.421.0
"@aws-sdk/credential-provider-web-identity": 3.418.0
"@aws-sdk/types": 3.418.0
"@smithy/credential-provider-imds": ^2.0.0
@@ -267,18 +267,18 @@ __metadata:
"@smithy/shared-ini-file-loader": ^2.0.6
"@smithy/types": ^2.3.3
tslib: ^2.5.0
- checksum: c519d15523d872c3d3249df48e513e7c648f1668bb9baec6af895613fcdf14f552d917337585bed744260796b5f0bd033215102c1bbceb588d46738b7d5093d1
+ checksum: 038e115250a966a28b43faa6a70ef4e9d543d51e0eed8446d0939c44a7a0c3333a3dcb0a80aa5c2b328cc225228aef8f8aa5b31ba1725316b3019b88ad091ad8
languageName: node
linkType: hard
-"@aws-sdk/credential-provider-node@npm:3.418.0":
- version: 3.418.0
- resolution: "@aws-sdk/credential-provider-node@npm:3.418.0"
+"@aws-sdk/credential-provider-node@npm:3.421.0":
+ version: 3.421.0
+ resolution: "@aws-sdk/credential-provider-node@npm:3.421.0"
dependencies:
"@aws-sdk/credential-provider-env": 3.418.0
- "@aws-sdk/credential-provider-ini": 3.418.0
+ "@aws-sdk/credential-provider-ini": 3.421.0
"@aws-sdk/credential-provider-process": 3.418.0
- "@aws-sdk/credential-provider-sso": 3.418.0
+ "@aws-sdk/credential-provider-sso": 3.421.0
"@aws-sdk/credential-provider-web-identity": 3.418.0
"@aws-sdk/types": 3.418.0
"@smithy/credential-provider-imds": ^2.0.0
@@ -286,7 +286,7 @@ __metadata:
"@smithy/shared-ini-file-loader": ^2.0.6
"@smithy/types": ^2.3.3
tslib: ^2.5.0
- checksum: bbaf9d9f4c7b7ab0c9b5772e3abcb6642021d8d10081f31ad4de34d1ba0522d9dc817aced7f28e2b8fff443177cfe90c295c0263f96be61d8c4e3849b44cb7c7
+ checksum: 0b0249ebc58383e7149f8b5398ca8d6af93df397fae4c0feaea9debd4617a90d7c9a01486709173799edaf06c6c34e9c979969da1a41bdb681d01c6661e6e0e3
languageName: node
linkType: hard
@@ -303,18 +303,18 @@ __metadata:
languageName: node
linkType: hard
-"@aws-sdk/credential-provider-sso@npm:3.418.0":
- version: 3.418.0
- resolution: "@aws-sdk/credential-provider-sso@npm:3.418.0"
+"@aws-sdk/credential-provider-sso@npm:3.421.0":
+ version: 3.421.0
+ resolution: "@aws-sdk/credential-provider-sso@npm:3.421.0"
dependencies:
- "@aws-sdk/client-sso": 3.418.0
+ "@aws-sdk/client-sso": 3.421.0
"@aws-sdk/token-providers": 3.418.0
"@aws-sdk/types": 3.418.0
"@smithy/property-provider": ^2.0.0
"@smithy/shared-ini-file-loader": ^2.0.6
"@smithy/types": ^2.3.3
tslib: ^2.5.0
- checksum: e666dd10f50b9510b09f64bdac66f97ac18e1521bdb6fd642c1446740fbeaf5d7a609dfb5c7166561cb5cecd5149b0ae08d9b9df919641168c022657f297414d
+ checksum: 7fd59a74fe28602ac0877c9e845a95a95a3be91869be33776576c2cbe41cce8b5921480e769a1fdf02db41f67d792e9f1ea93d9e5f0256736cea8f24d8839b24
languageName: node
linkType: hard
@@ -3774,9 +3774,9 @@ __metadata:
linkType: hard
"@eslint-community/regexpp@npm:^4.6.1":
- version: 4.8.1
- resolution: "@eslint-community/regexpp@npm:4.8.1"
- checksum: 82d62c845ef42b810f268cfdc84d803a2da01735fb52e902fd34bdc09f92464a094fd8e4802839874b000b2f73f67c972859e813ba705233515d3e954f234bf2
+ version: 4.9.0
+ resolution: "@eslint-community/regexpp@npm:4.9.0"
+ checksum: 82411f0643ab9bfd271bf12c8c75031266b13595d9371585ee3b0d680d918d4abf37c7e94d0da22e45817c9bbc59b79dfcbd672050dfb00af88fb89c80fd420f
languageName: node
linkType: hard
@@ -4254,12 +4254,12 @@ __metadata:
linkType: hard
"@grpc/grpc-js@npm:^1.3.2":
- version: 1.9.3
- resolution: "@grpc/grpc-js@npm:1.9.3"
+ version: 1.9.4
+ resolution: "@grpc/grpc-js@npm:1.9.4"
dependencies:
"@grpc/proto-loader": ^0.7.8
"@types/node": ">=12.12.47"
- checksum: 09634de9f871a17c95db95338fe472522d5dca0f77b622e3a497ef806262813445ba1a1f3261f03461d84ac985e420317d5638b3314fcb524ee2e47e512ffa64
+ checksum: 83616d3727f16d9caf57fb16f8525e6884856569624a244ef8dde2873b7d7a439d302fd0a82d28bbbf9ba9777d3b25a58c706e35daa30120abb04f1646aa0e11
languageName: node
linkType: hard
@@ -8386,11 +8386,11 @@ __metadata:
linkType: hard
"@types/istanbul-lib-report@npm:*":
- version: 3.0.0
- resolution: "@types/istanbul-lib-report@npm:3.0.0"
+ version: 3.0.1
+ resolution: "@types/istanbul-lib-report@npm:3.0.1"
dependencies:
"@types/istanbul-lib-coverage": "*"
- checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36
+ checksum: cfc66de48577bb7b2636a6afded7056483693c3ea70916276518cdfaa0d4b51bf564ded88fb13e75716665c3af3d4d54e9c2de042c0219dcabad7e81c398688b
languageName: node
linkType: hard
@@ -8405,11 +8405,11 @@ __metadata:
linkType: hard
"@types/istanbul-reports@npm:^3.0.0":
- version: 3.0.1
- resolution: "@types/istanbul-reports@npm:3.0.1"
+ version: 3.0.2
+ resolution: "@types/istanbul-reports@npm:3.0.2"
dependencies:
"@types/istanbul-lib-report": "*"
- checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903
+ checksum: f52028d6fe4d28f0085dd7ed66ccfa6af632579e9a4091b90928ffef93d4dbec0bacd49e9caf1b939d05df9eafc5ac1f5939413cdf8ac59fbe4b29602d4d0939
languageName: node
linkType: hard
@@ -8460,46 +8460,46 @@ __metadata:
linkType: hard
"@types/mdast@npm:^3.0.0":
- version: 3.0.12
- resolution: "@types/mdast@npm:3.0.12"
+ version: 3.0.13
+ resolution: "@types/mdast@npm:3.0.13"
dependencies:
"@types/unist": ^2
- checksum: 83adb8679b9d139f69f63554d120af921e9f1289e9903a2c99e0554a327c8524a6c0beccdc0721e4fdbccc606e81964fecb0d390d53df0f74360938e22f1a469
+ checksum: f13fa17a2931ed1492a2f0012a3abd6de3a2d1128145981321909e03fedba80162668f284a4af92aca3732b27e933c5f4772336d96b9ae660bfde696d07abbe6
languageName: node
linkType: hard
"@types/mdurl@npm:^1.0.0":
- version: 1.0.2
- resolution: "@types/mdurl@npm:1.0.2"
- checksum: 79c7e523b377f53cf1f5a240fe23d0c6cae856667692bd21bf1d064eafe5ccc40ae39a2aa0a9a51e8c94d1307228c8f6b121e847124591a9a828c3baf65e86e2
+ version: 1.0.3
+ resolution: "@types/mdurl@npm:1.0.3"
+ checksum: 5bbed4f0eb9f60040fa26be77aa2158ca468b6423876cec0d2043e7f8298e83b8e5b95fb66056327b02d747c4d376aed16c11ff3fdc4cb3dca327a6931a71f18
languageName: node
linkType: hard
"@types/mdx@npm:^2.0.0":
- version: 2.0.7
- resolution: "@types/mdx@npm:2.0.7"
- checksum: c746659ebea471535d99a49cc935dc9f831fac22def3fa8c8a0883ad2cae71c4cca1d8563fa60d0e2730b14cb13e95c32af8dfda455a4937476a7d9e2748d641
+ version: 2.0.8
+ resolution: "@types/mdx@npm:2.0.8"
+ checksum: 4a7c2241c37e87aaab044c561f24874fabcd5cd2d6feb28dc665e2c80562afa7ddf94391a3b8ab3f76041199c8bafcff9131acf6d060f1aca45d763b171bbc29
languageName: node
linkType: hard
"@types/mime-types@npm:^2.1.0":
- version: 2.1.1
- resolution: "@types/mime-types@npm:2.1.1"
- checksum: 106b5d556add46446a579ad25ff15d6b421851790d887edcad558c90c1e64b1defc72bfbaf4b08f208916e21d9cc45cdb951d77be51268b18221544cfe054a3c
+ version: 2.1.2
+ resolution: "@types/mime-types@npm:2.1.2"
+ checksum: 9e3c78f1c63211e0450901212566a046da68d4438a5e543333ec9b0be3259bd5d01532734dc51ead40104889b98d12c7663b65212a318aafad3e34c98204e9e1
languageName: node
linkType: hard
"@types/mime@npm:*":
- version: 3.0.1
- resolution: "@types/mime@npm:3.0.1"
- checksum: 4040fac73fd0cea2460e29b348c1a6173da747f3a87da0dbce80dd7a9355a3d0e51d6d9a401654f3e5550620e3718b5a899b2ec1debf18424e298a2c605346e7
+ version: 3.0.2
+ resolution: "@types/mime@npm:3.0.2"
+ checksum: 09cf74f6377d1b27f4a24512cb689ad30af59880ac473ed6f7bc5285ecde88bbe8fe500789340ad57810da9d6fe1704f86e8bfe147b9ea76d58925204a60b906
languageName: node
linkType: hard
"@types/mime@npm:^1":
- version: 1.3.2
- resolution: "@types/mime@npm:1.3.2"
- checksum: 0493368244cced1a69cb791b485a260a422e6fcc857782e1178d1e6f219f1b161793e9f87f5fae1b219af0f50bee24fcbe733a18b4be8fdd07a38a8fb91146fd
+ version: 1.3.3
+ resolution: "@types/mime@npm:1.3.3"
+ checksum: 7e27dede6517c1d604821a8a5412d6b7131decc8397ad4bac9216fc90dea26c9571426623ebeea2a9b89dbfb89ad98f7370a3c62cd2be8896c6e897333b117c9
languageName: node
linkType: hard
@@ -8511,18 +8511,18 @@ __metadata:
linkType: hard
"@types/morgan@npm:^1.9.4":
- version: 1.9.5
- resolution: "@types/morgan@npm:1.9.5"
+ version: 1.9.6
+ resolution: "@types/morgan@npm:1.9.6"
dependencies:
"@types/node": "*"
- checksum: f98deb4c7f2ad6049ad34ed7b0f0d427546bdf2358011070af9d597de1b0a03b38cc10cfe65ef2e7673e569c384303d949e76df701acefe288d547f614142973
+ checksum: 6525248325a74342f929c958be69c0840c8f3a288e003a8904319cae92e531f17a8aa2700701e66775adcca7f9506dd630fec2f95dc04a3e73add04fde42aab8
languageName: node
linkType: hard
"@types/ms@npm:*":
- version: 0.7.31
- resolution: "@types/ms@npm:0.7.31"
- checksum: daadd354aedde024cce6f5aa873fefe7b71b22cd0e28632a69e8b677aeb48ae8caa1c60e5919bb781df040d116b01cb4316335167a3fc0ef6a63fa3614c0f6da
+ version: 0.7.32
+ resolution: "@types/ms@npm:0.7.32"
+ checksum: 610744605c5924aa2657c8a62d307052af4f0e38e2aa015f154ef03391fabb4fd903f9c9baacb41f6e5798b8697e898463c351e5faf638738603ed29137b5254
languageName: node
linkType: hard
@@ -8537,9 +8537,9 @@ __metadata:
linkType: hard
"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0":
- version: 20.6.5
- resolution: "@types/node@npm:20.6.5"
- checksum: b849e849cf7631458a65c5019c81962028e306d8c4455a48422277b240f5a7eb8a1f1dafa60306bd4c773b77263bb8b05c074b1026e868bd137bb2022cf63ea2
+ version: 20.7.1
+ resolution: "@types/node@npm:20.7.1"
+ checksum: 3140bd6c9130f1ed73a78ce7a1765ee43e155c1eea50eea45e18faeb31d11d97a84fffdc5e3a97582101d2f57d2652a50f510ede6c702780267bad74c822d56c
languageName: node
linkType: hard
@@ -8551,9 +8551,9 @@ __metadata:
linkType: hard
"@types/node@npm:^18.15.5":
- version: 18.17.19
- resolution: "@types/node@npm:18.17.19"
- checksum: 6ab47127cd7534511aa199550659d56b44e5a6dbec9df054d0cde279926b4d43f0e6438f92c8392b039ab4e2a85aa0f698b95926430aff860e23bfc36c96576c
+ version: 18.18.0
+ resolution: "@types/node@npm:18.18.0"
+ checksum: 61bcffa28eb713e7a4c66fd369df603369c3f834a783faeced95fe3e78903faa25f1a704d49e054f41d71b7915eeb066d10a37cc699421fcf5dd267f96ad5808
languageName: node
linkType: hard
@@ -8616,27 +8616,27 @@ __metadata:
linkType: hard
"@types/range-parser@npm:*":
- version: 1.2.4
- resolution: "@types/range-parser@npm:1.2.4"
- checksum: b7c0dfd5080a989d6c8bb0b6750fc0933d9acabeb476da6fe71d8bdf1ab65e37c136169d84148034802f48378ab94e3c37bb4ef7656b2bec2cb9c0f8d4146a95
+ version: 1.2.5
+ resolution: "@types/range-parser@npm:1.2.5"
+ checksum: db9aaa04a02d019395a9a4346475669a2864a32a6477ad0fc457bd2ef39a167cabe742f55a8a3fa8bc90abac795b716c22b37348bc3e19313ebe6c9310815233
languageName: node
linkType: hard
"@types/reach__router@npm:^1.2.3":
- version: 1.3.11
- resolution: "@types/reach__router@npm:1.3.11"
+ version: 1.3.12
+ resolution: "@types/reach__router@npm:1.3.12"
dependencies:
"@types/react": "*"
- checksum: 6bcf40714e0dafff66cbf10a534320eae35dae8344f616d2ddf077937287a0df188dfbfb32fb8045cbc641139d1ab69ee5bb258a51642823cadefbcda020a044
+ checksum: df838ba6bc3463c50ae35e704e11a9073bb0617c04676887a9ad87177b078d6593aa3cd8b63de07e791ac8b86183dbb0f20072c22dd40754487a47f0064c3fb7
languageName: node
linkType: hard
"@types/react-dom@npm:*, @types/react-dom@npm:^18.0.11":
- version: 18.2.7
- resolution: "@types/react-dom@npm:18.2.7"
+ version: 18.2.8
+ resolution: "@types/react-dom@npm:18.2.8"
dependencies:
"@types/react": "*"
- checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f
+ checksum: d36264631028d021b73cd9e015f10b95c4959ae1ce8f7a7419f318d1f05b1d063e6afffcd2a349a6bccd64ccc9ee9d2d976e1f0437643f0e7db621fa035bca65
languageName: node
linkType: hard
@@ -8659,13 +8659,13 @@ __metadata:
linkType: hard
"@types/react@npm:*, @types/react@npm:>=16, @types/react@npm:^18.0.28":
- version: 18.2.22
- resolution: "@types/react@npm:18.2.22"
+ version: 18.2.23
+ resolution: "@types/react@npm:18.2.23"
dependencies:
"@types/prop-types": "*"
"@types/scheduler": "*"
csstype: ^3.0.2
- checksum: 44289523dabaadcd3fd85689abb98f9ebcc8492d7e978348d1c986138acef4801030b279e89a19e38a6319e294bcea77559e37e0c803e4bacf2b8ae3a56ba587
+ checksum: efb9d1ed1940c0e7ba08a21ffba5e266d8dbbb8fe618cfb97bc902dfc96385fdd8189e3f7f64b4aa13134f8e61947d60560deb23be151253c3a97b0d070897ca
languageName: node
linkType: hard
@@ -8677,55 +8677,55 @@ __metadata:
linkType: hard
"@types/scheduler@npm:*":
- version: 0.16.3
- resolution: "@types/scheduler@npm:0.16.3"
- checksum: 2b0aec39c24268e3ce938c5db2f2e77f5c3dd280e05c262d9c2fe7d890929e4632a6b8e94334017b66b45e4f92a5aa42ba3356640c2a1175fa37bef2f5200767
+ version: 0.16.4
+ resolution: "@types/scheduler@npm:0.16.4"
+ checksum: a57b0f10da1b021e6bd5eeef8a1917dd3b08a8715bd8029e2ded2096d8f091bb1bb1fef2d66e139588a983c4bfbad29b59e48011141725fa83c76e986e1257d7
languageName: node
linkType: hard
"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4":
- version: 7.5.2
- resolution: "@types/semver@npm:7.5.2"
- checksum: 743aa8a2b58e20b329c19bd2459152cb049d12fafab7279b90ac11e0f268c97efbcb606ea0c681cca03f79015381b40d9b1244349b354270bec3f939ed49f6e9
+ version: 7.5.3
+ resolution: "@types/semver@npm:7.5.3"
+ checksum: 349fdd1ab6c213bac5c991bac766bd07b8b12e63762462bb058740dcd2eb09c8193d068bb226f134661275f2022976214c0e727a4e5eb83ec1b131127c980d3e
languageName: node
linkType: hard
"@types/send@npm:*":
- version: 0.17.1
- resolution: "@types/send@npm:0.17.1"
+ version: 0.17.2
+ resolution: "@types/send@npm:0.17.2"
dependencies:
"@types/mime": ^1
"@types/node": "*"
- checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793
+ checksum: 1ff5b1bd6a4f6fdc6402c7024781ff5dbd0e1f51a43c69529fb67c710943c7416d2f0d77c57c70fccf6616f25f838f32f960284526e408d4edae2e91e1fce95a
languageName: node
linkType: hard
"@types/serve-index@npm:^1.9.1":
- version: 1.9.1
- resolution: "@types/serve-index@npm:1.9.1"
+ version: 1.9.2
+ resolution: "@types/serve-index@npm:1.9.2"
dependencies:
"@types/express": "*"
- checksum: 026f3995fb500f6df7c3fe5009e53bad6d739e20b84089f58ebfafb2f404bbbb6162bbe33f72d2f2af32d5b8d3799c8e179793f90d9ed5871fb8591190bb6056
+ checksum: 4fd0a8fcdd6e2b2d7704a539b7c1e0d143e9e00be4c3992394fe2ef7e9b67283d74b43db3f92b0e0717d779aa51184168bbae617d30456357cb95ec58aa59ea8
languageName: node
linkType: hard
"@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10":
- version: 1.15.2
- resolution: "@types/serve-static@npm:1.15.2"
+ version: 1.15.3
+ resolution: "@types/serve-static@npm:1.15.3"
dependencies:
"@types/http-errors": "*"
"@types/mime": "*"
"@types/node": "*"
- checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e
+ checksum: afa52252f0ba94cdb5391e80f23e17fd629bdf2a31be8876e2c4490312ed6b0570822dd7de7cea04c9002049e207709563568b7f4ee10bb9f456321db1e83e40
languageName: node
linkType: hard
"@types/sockjs@npm:^0.3.33":
- version: 0.3.33
- resolution: "@types/sockjs@npm:0.3.33"
+ version: 0.3.34
+ resolution: "@types/sockjs@npm:0.3.34"
dependencies:
"@types/node": "*"
- checksum: b9bbb2b5c5ead2fb884bb019f61a014e37410bddd295de28184e1b2e71ee6b04120c5ba7b9954617f0bdf962c13d06249ce65004490889c747c80d3f628ea842
+ checksum: 1d38b1976a97f5895a6be00cead1b2a59d842f023b6e35450b7eec8a3131c860c447aba3f7ea3c880c066d8277b0c76fae9d080be1aad475811b568ed6079d49
languageName: node
linkType: hard
@@ -8737,13 +8737,13 @@ __metadata:
linkType: hard
"@types/styled-components@npm:^5.1.26":
- version: 5.1.27
- resolution: "@types/styled-components@npm:5.1.27"
+ version: 5.1.28
+ resolution: "@types/styled-components@npm:5.1.28"
dependencies:
"@types/hoist-non-react-statics": "*"
"@types/react": "*"
csstype: ^3.0.2
- checksum: 6f8d99642f09f28a233a5bf93d3139389c3bf5e4c643620881cb286f581d6844f3c1c43be5bd9405d3b199b6a858bd8b0ec6ccbb17b2304a88d70e2a6f91a996
+ checksum: 2e12be4fdc2d60f63e16f8f5cac98d8305e0686b3332a160fec39df2a277f16715b878e25384ddda29e48acf101110a29ca108b716296e9a06bf2740f1257385
languageName: node
linkType: hard
@@ -8798,9 +8798,9 @@ __metadata:
linkType: hard
"@types/webpack-env@npm:^1.16.0":
- version: 1.18.1
- resolution: "@types/webpack-env@npm:1.18.1"
- checksum: 3173c069763e51a96565d602af7e6dac9d772ae4aa6f26cac187cbf599a7f0b88f790b4b050b9dbdb0485daed3061b4a337863f3b8ce66f8a4e51f75ad387c6a
+ version: 1.18.2
+ resolution: "@types/webpack-env@npm:1.18.2"
+ checksum: 883908ade827d35a10efc574fb6f2728a7c520d4296cf1507633ac7457204ccd697bc6c8cadac99bc5d96074a6109c658ebfde59f42ba5ba0fdfffc538892b0f
languageName: node
linkType: hard
@@ -8814,11 +8814,11 @@ __metadata:
linkType: hard
"@types/ws@npm:*, @types/ws@npm:^8.5.1, @types/ws@npm:^8.5.4":
- version: 8.5.5
- resolution: "@types/ws@npm:8.5.5"
+ version: 8.5.6
+ resolution: "@types/ws@npm:8.5.6"
dependencies:
"@types/node": "*"
- checksum: d00bf8070e6938e3ccf933010921c6ce78ac3606696ce37a393b27a9a603f7bd93ea64f3c5fa295a2f743575ba9c9a9fdb904af0f5fe2229bf2adf0630386e4a
+ checksum: 7addb0c5fa4e7713d5209afb8a90f1852b12c02cb537395adf7a05fbaf21205dc5f7c110fd5ad6f3dbf147112cbff33fb11d8633059cb344f0c14f595b1ea1fb
languageName: node
linkType: hard
@@ -10813,16 +10813,16 @@ __metadata:
linkType: hard
"browserslist@npm:^4.14.5, browserslist@npm:^4.21.10, browserslist@npm:^4.21.9, browserslist@npm:^4.9.1":
- version: 4.21.11
- resolution: "browserslist@npm:4.21.11"
+ version: 4.22.0
+ resolution: "browserslist@npm:4.22.0"
dependencies:
- caniuse-lite: ^1.0.30001538
- electron-to-chromium: ^1.4.526
+ caniuse-lite: ^1.0.30001539
+ electron-to-chromium: ^1.4.530
node-releases: ^2.0.13
update-browserslist-db: ^1.0.13
bin:
browserslist: cli.js
- checksum: 89377745428d32c7bbec37055bc4b9e48aa859418ea3886b13218d825f8ea3053640f90d8652844ae855941fec0bffd2d69cf933035d6f9224b427d48d31eddf
+ checksum: 14fc119bbfb85b65e2ee4a82205fabf9327520d010c4c586f1176ceaf9136cfdb391397045a4eafaa9defe52b6dbdf875916714695826c69091a936d5838f9ec
languageName: node
linkType: hard
@@ -11040,10 +11040,10 @@ __metadata:
languageName: node
linkType: hard
-"caniuse-lite@npm:^1.0.30001538":
- version: 1.0.30001539
- resolution: "caniuse-lite@npm:1.0.30001539"
- checksum: 8595905d6c7234173a4915439fdd69fa2c06b0272d56af63aee0df6114e1ee4727758af160c0db9844055f778e0ea27ed4714facf2e472a2e74d9f567f111f41
+"caniuse-lite@npm:^1.0.30001539":
+ version: 1.0.30001541
+ resolution: "caniuse-lite@npm:1.0.30001541"
+ checksum: 972f6c223cf4ea2c6821b817b419249285006bbf67ebe415fe58097cf07551e3bae898586736d92f7c40b9f0ac28638dbf760631c23742b780affd0254f44d17
languageName: node
linkType: hard
@@ -13061,10 +13061,10 @@ __metadata:
languageName: node
linkType: hard
-"electron-to-chromium@npm:^1.4.526":
- version: 1.4.528
- resolution: "electron-to-chromium@npm:1.4.528"
- checksum: e9b249929e012ce6c25f8d1e1965e7fb19a426cc72fdf72026a0ce010846ec1b0efe2730b1a1f3d1c98bd11200b94b73431bc5279211a9f4a28f2389e690c39c
+"electron-to-chromium@npm:^1.4.530":
+ version: 1.4.532
+ resolution: "electron-to-chromium@npm:1.4.532"
+ checksum: e9f77b5d6df84aa1f7598359ec2c988c3758e58106e63f2a0a6dc4756a6733b126316e61a79a2a6643aa2a0f9a1cf9ebe66c817dcb970a3fc9d8190342ef070a
languageName: node
linkType: hard
@@ -14793,9 +14793,9 @@ __metadata:
linkType: hard
"fs-monkey@npm:^1.0.4":
- version: 1.0.4
- resolution: "fs-monkey@npm:1.0.4"
- checksum: 8b254c982905c0b7e028eab22b410dc35a5c0019c1c860456f5f54ae6a61666e1cb8c6b700d6c88cc873694c00953c935847b9959cc4dcf274aacb8673c1e8bf
+ version: 1.0.5
+ resolution: "fs-monkey@npm:1.0.5"
+ checksum: 424b67f65b37fe66117ae2bb061f790fe6d4b609e1d160487c74b3d69fbf42f262c665ccfba32e8b5f113f96f92e9a58fcdebe42d5f6649bdfc72918093a3119
languageName: node
linkType: hard
@@ -15109,17 +15109,17 @@ __metadata:
linkType: hard
"glob@npm:^10.2.2":
- version: 10.3.7
- resolution: "glob@npm:10.3.7"
+ version: 10.3.10
+ resolution: "glob@npm:10.3.10"
dependencies:
foreground-child: ^3.1.0
- jackspeak: ^2.0.3
+ jackspeak: ^2.3.5
minimatch: ^9.0.1
minipass: ^5.0.0 || ^6.0.2 || ^7.0.0
path-scurry: ^1.10.1
bin:
glob: dist/esm/bin.mjs
- checksum: 9a27f1fa8774c3a8ab8f05c26a77276edaf5418aac29aff70c5d847ef75dabf536554cb113e945193323fb769fbe32edde12559d2d52266f38662595cbc7a031
+ checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3
languageName: node
linkType: hard
@@ -16941,16 +16941,16 @@ __metadata:
languageName: node
linkType: hard
-"jackspeak@npm:^2.0.3":
- version: 2.3.3
- resolution: "jackspeak@npm:2.3.3"
+"jackspeak@npm:^2.3.5":
+ version: 2.3.6
+ resolution: "jackspeak@npm:2.3.6"
dependencies:
"@isaacs/cliui": ^8.0.2
"@pkgjs/parseargs": ^0.11.0
dependenciesMeta:
"@pkgjs/parseargs":
optional: true
- checksum: 4313a7c0cc44c7753c4cb9869935f0b06f4cf96827515f63f58ff46b3d2f6e29aba6b3b5151778397c3f5ae67ef8bfc48871967bd10343c27e90cff198ec7808
+ checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54
languageName: node
linkType: hard
@@ -21563,8 +21563,8 @@ __metadata:
linkType: hard
"rc-virtual-list@npm:^3.5.1":
- version: 3.11.1
- resolution: "rc-virtual-list@npm:3.11.1"
+ version: 3.11.2
+ resolution: "rc-virtual-list@npm:3.11.2"
dependencies:
"@babel/runtime": ^7.20.0
classnames: ^2.2.6
@@ -21573,7 +21573,7 @@ __metadata:
peerDependencies:
react: "*"
react-dom: "*"
- checksum: bd6b41b2ca452313534d4d5d1dc0efcb5baf1e26b815acf3553e69f96bb7eeb0980319284adf389f4bcc3f934265d08e8d7e193fb4677a3643bbd896080bced6
+ checksum: b642e55ca2c4b56fb2048b5151a17e2f0f1c15cf3f4d8a26a4f1f370c95a6f4476743886b6633f083f107c82fbe86c5548bbf37b7e2f8b79615d90b62777824e
languageName: node
linkType: hard
@@ -21794,15 +21794,15 @@ __metadata:
linkType: hard
"react-draggable@npm:^4.4.5":
- version: 4.4.5
- resolution: "react-draggable@npm:4.4.5"
+ version: 4.4.6
+ resolution: "react-draggable@npm:4.4.6"
dependencies:
clsx: ^1.1.1
prop-types: ^15.8.1
peerDependencies:
react: ">= 16.3.0"
react-dom: ">= 16.3.0"
- checksum: 21c3775db086e13020967627c20acd41d1ddbc7c7d7fca51491a5bbb54a0aa7e1730a4bc9af17141eb50a4954e547a5e25b2368f5f54b70db6f2686a897bacf2
+ checksum: 9b15aac59244873ac4561c5a2bead43a56e18d406e0a5f242bd4f9d151c074530c02b99387983104bf43417292f9cf8d063e554ed08d88792235e3fbc965f1b8
languageName: node
linkType: hard
@@ -22283,15 +22283,15 @@ __metadata:
linkType: hard
"react-tooltip@npm:^5.21.1":
- version: 5.21.4
- resolution: "react-tooltip@npm:5.21.4"
+ version: 5.21.5
+ resolution: "react-tooltip@npm:5.21.5"
dependencies:
"@floating-ui/dom": ^1.0.0
classnames: ^2.3.0
peerDependencies:
react: ">=16.14.0"
react-dom: ">=16.14.0"
- checksum: 9b663c5d9a1472b96d3ed708ecce01052aed267dc739520c9b55389a5e42c195a6bcd0717219f260bf0dadee2452d80a7c5fa14c5c3f8b5cdc6a9174d7f42d4a
+ checksum: 067d6a5bc7c6b12b2ae054f855416b068bcc9fe59864b83c655e775066d6f81728b2ec13e80565968da7ce35c7c0286f8e154c635a1e79bb7a8233df8a356c51
languageName: node
linkType: hard
@@ -23300,7 +23300,14 @@ __metadata:
languageName: node
linkType: hard
-"sax@npm:^1.2.4, sax@npm:~1.2.1, sax@npm:~1.2.4":
+"sax@npm:^1.2.4":
+ version: 1.3.0
+ resolution: "sax@npm:1.3.0"
+ checksum: 238ab3a9ba8c8f8aaf1c5ea9120386391f6ee0af52f1a6a40bbb6df78241dd05d782f2359d614ac6aae08c4c4125208b456548a6cf68625aa4fe178486e63ecd
+ languageName: node
+ linkType: hard
+
+"sax@npm:~1.2.1, sax@npm:~1.2.4":
version: 1.2.4
resolution: "sax@npm:1.2.4"
checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe