Skip to content

Commit

Permalink
Merge branch 'hotfix/v3.0.1' into develop
Browse files Browse the repository at this point in the history
# Conflicts:
#	products/ASC.Files/Core/Utils/EntryManager.cs
#	web/ASC.Web.Api/Api/AuthenticationController.cs
  • Loading branch information
pavelbannov committed Dec 9, 2024
2 parents 4402703 + ffa6665 commit e9d6a36
Show file tree
Hide file tree
Showing 37 changed files with 361 additions and 116 deletions.
3 changes: 3 additions & 0 deletions common/ASC.Api.Core/Log/CustomExceptionHandlerLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ internal static partial class CustomExceptionHandlerLogger
{
[LoggerMessage(LogLevel.Critical, "error during executing {RequestMethod}: {PathValue}")]
public static partial void CriticalError(this ILogger<CustomExceptionHandler> logger, string RequestMethod, string PathValue, Exception exception);

[LoggerMessage(LogLevel.Information, "error during executing {RequestMethod}: {PathValue} {ExceptionMessage} {InnerExceptionMessage}")]
public static partial void InformationError(this ILogger<CustomExceptionHandler> logger, string RequestMethod, string PathValue, string ExceptionMessage, string InnerExceptionMessage);
}
11 changes: 10 additions & 1 deletion common/ASC.Api.Core/Middleware/ResponseWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception excep
}

var withStackTrace = true;
var criticalException = true;

switch (exception)
{
Expand All @@ -64,6 +65,7 @@ public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception excep
case AuthenticationException:
status = HttpStatusCode.Unauthorized;
withStackTrace = false;
criticalException = false;
break;
case InvalidOperationException:
status = HttpStatusCode.Forbidden;
Expand All @@ -82,7 +84,14 @@ public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception excep
break;
}

logger.CriticalError(context.Request.Method, context.Request.Path.Value, exception);
if (criticalException)
{
logger.CriticalError(context.Request.Method, context.Request.Path.Value, exception);
}
else
{
logger.InformationError(context.Request.Method, context.Request.Path.Value, exception.Message, exception.InnerException?.Message);
}

var result = new ErrorApiResponse(status, exception, message, withStackTrace);

Expand Down
5 changes: 5 additions & 0 deletions common/ASC.Core.Common/Billing/License/License.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public class License
[JsonPropertyName("signature")]
public string Signature { get; set; }

/// <summary>Indicates whether the license is a developer license or not</summary>
/// <type>System.Boolean, System</type>
[JsonPropertyName("docspace_dev")]
public bool Developer { get; set; }

public static License Parse(string licenseString)
{
if (string.IsNullOrEmpty(licenseString))
Expand Down
2 changes: 1 addition & 1 deletion common/ASC.Core.Common/Billing/License/LicenseReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ private static async Task SaveLicenseAsync(Stream licenseStream, string path)

private DateTime Validate(License license)
{
var invalidLicenseType = _licenseType == LicenseType.Enterprise ? license.Customization : !license.Customization;
var invalidLicenseType = _licenseType == LicenseType.Enterprise ? license.Developer : !license.Developer;

if (string.IsNullOrEmpty(license.CustomerId)
|| string.IsNullOrEmpty(license.Signature)
Expand Down
8 changes: 6 additions & 2 deletions common/ASC.SsoAuth/app/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ module.exports = function (app, config) {
return res.redirect(request.context);
}
}
function getValueByKeyIgnoreCase(obj, key) {
const entry = Object.entries(obj).find(([k]) => k.toLowerCase() === key.toLowerCase());
return entry ? entry[1] : undefined;
}

const createAuthnTemplateCallback = (_idp, _sp, method) => (template) => {
const metadata = { idp: _idp.entityMeta, sp: _sp.entityMeta };
Expand Down Expand Up @@ -567,8 +571,8 @@ module.exports = function (app, config) {

//const logoutUser = new LogoutModel(userData.NameId, userData.SessionId);
const user = {
logoutNameID: userData.NameId,
sessionIndex: userData.SessionId,
logoutNameID: getValueByKeyIgnoreCase(userData, "NameId"),
sessionIndex: getValueByKeyIgnoreCase(userData, "SessionId")
};

const data = sp.createLogoutRequest(
Expand Down
8 changes: 5 additions & 3 deletions products/ASC.Files/Core/ApiModels/Binders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,25 @@ internal static List<JsonElement> ParseQuery(this ModelBindingContext bindingCon
return ParseQuery(bindingContext, $"{modelName}[]");
}

internal static IEnumerable<ItemKeyValuePair<JsonElement, string>> ParseDictionary(this ModelBindingContext bindingContext, string modelName)
internal static IEnumerable<DownloadRequestItemDto> ParseDictionary(this ModelBindingContext bindingContext, string modelName)
{
var result = new List<ItemKeyValuePair<JsonElement, string>>();
var result = new List<DownloadRequestItemDto>();

for (var i = 0; ; i++)
{
var keyProviderResult = bindingContext.ValueProvider.GetValue($"{modelName}[{i}][key]");
var valueProviderResult = bindingContext.ValueProvider.GetValue($"{modelName}[{i}][value]");
var passwordProviderResult = bindingContext.ValueProvider.GetValue($"{modelName}[{i}][password]");

if (keyProviderResult != ValueProviderResult.None && valueProviderResult != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(modelName, keyProviderResult);
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
bindingContext.ModelState.SetModelValue(modelName, passwordProviderResult);

if (!string.IsNullOrEmpty(keyProviderResult.FirstValue) && !string.IsNullOrEmpty(valueProviderResult.FirstValue))
{
result.Add(new ItemKeyValuePair<JsonElement, string> { Key = ParseQueryParam(keyProviderResult.FirstValue), Value = valueProviderResult.FirstValue });
result.Add(new DownloadRequestItemDto { Key = ParseQueryParam(keyProviderResult.FirstValue), Value = valueProviderResult.FirstValue, Password = passwordProviderResult.FirstValue });
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ public class DownloadRequestDto : BaseBatchRequestDto
/// <summary>
/// List of file IDs which will be converted
/// </summary>
public IEnumerable<ItemKeyValuePair<JsonElement, string>> FileConvertIds { get; set; } = new List<ItemKeyValuePair<JsonElement, string>>();
public IEnumerable<DownloadRequestItemDto> FileConvertIds { get; set; } = new List<DownloadRequestItemDto>();
}

public class DownloadRequestItemDto
{
public JsonElement Key { get; init; }
public string Value { get; init; }
public string Password { get; init; }
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,7 @@ public class ExternalShareDto : IMapFrom<ValidationInfo>
/// Link ID
/// </summary>
public Guid LinkId { get; set; }

/// <summary>Specifies whether the user is authenticated or not</summary>
public bool IsAuthenticated { get; set; }
}
17 changes: 14 additions & 3 deletions products/ASC.Files/Core/ApiModels/ResponseDto/FileDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,22 @@ private async Task<FileDto<T>> GetFileWrapperAsync<T>(File<T> file, string order

if (fileType == FileType.Pdf)
{
var linkDao = daoFactory.GetLinkDao<T>();
var folderDao = daoFactory.GetCacheFolderDao<T>();

var linkedIdTask = linkDao.GetLinkedAsync(file.Id);
var propertiesTask = fileDao.GetProperties(file.Id);
Task<T> linkedIdTask;
Task<EntryProperties<T>> propertiesTask;

if (file.FormInfo != null)
{
linkedIdTask = Task.FromResult(file.FormInfo.LinkedId);
propertiesTask = Task.FromResult(file.FormInfo.Properties);
}
else
{
linkedIdTask = daoFactory.GetLinkDao<T>().GetLinkedAsync(file.Id);
propertiesTask = fileDao.GetProperties(file.Id);
}

var currentFolderTask = folderDao.GetFolderAsync(file.ParentId);
await Task.WhenAll(linkedIdTask, propertiesTask, currentFolderTask);

Expand Down
2 changes: 2 additions & 0 deletions products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> parentIds, FilterType fil

Task<EntryProperties<T>> GetProperties(T fileId);

Task<Dictionary<T, EntryProperties<T>>> GetPropertiesAsync(IEnumerable<T> filesIds);

Task SaveProperties(T fileId, EntryProperties<T> entryProperties);

Task<int> GetFilesCountAsync(T parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent,
Expand Down
1 change: 1 addition & 0 deletions products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public interface ILinkDao<T>
Task AddLinkAsync(T sourceId, T linkedId);
Task<T> GetSourceAsync(T linkedId);
Task<T> GetLinkedAsync(T sourceId);
Task<Dictionary<T, T>> GetLinkedIdsAsync(IEnumerable<T> sourceIds);
Task DeleteLinkAsync(T sourceId);
Task DeleteAllLinkAsync(T sourceId);
}
19 changes: 19 additions & 0 deletions products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,25 @@ public async Task<EntryProperties<int>> GetProperties(int fileId)
return data != null ? EntryProperties<int>.Deserialize(data, logger) : null;
}

public async Task<Dictionary<int, EntryProperties<int>>> GetPropertiesAsync(IEnumerable<int> filesIds)
{
var tenantId = _tenantManager.GetCurrentTenantId();
await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync();

var properties = await filesDbContext.FilesPropertiesAsync(tenantId, filesIds.Select(f => f.ToString())).ToListAsync();

var propertiesMap = new Dictionary<int, EntryProperties<int>>(properties.Count);
foreach (var property in properties)
{
if (int.TryParse(property.EntryId, out var id))
{
propertiesMap.TryAdd(id, EntryProperties<int>.Deserialize(property.Data, logger));
}
}

return propertiesMap;
}

public async Task SaveProperties(int fileId, EntryProperties<int> entryProperties)
{
string data;
Expand Down
16 changes: 16 additions & 0 deletions products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ public async Task<T> GetLinkedAsync(T sourceId)
return (T)Convert.ChangeType(fromDb, typeof(T));
}

public async Task<Dictionary<T, T>> GetLinkedIdsAsync(IEnumerable<T> sourceIds)
{
var tenantId = _tenantManager.GetCurrentTenantId();
var mapping = daoFactory.GetMapping<T>();

var mappedIds = await sourceIds.ToAsyncEnumerable().SelectAwait(async x => await mapping.MappingIdAsync(x)).ToListAsync();
var source = mappedIds.Select(x => x.ToString());

await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync();

return await filesDbContext.FilesLinksAsync(tenantId, source, _authContext.CurrentAccount.ID)
.ToDictionaryAsync(
x => (T)Convert.ChangeType(x.SourceId, typeof(T)),
x => (T)Convert.ChangeType(x.LinkedId, typeof(T)));
}

public async Task DeleteLinkAsync(T sourceId)
{
var tenantId = _tenantManager.GetCurrentTenantId();
Expand Down
13 changes: 13 additions & 0 deletions products/ASC.Files/Core/Core/EF/Queries/FileQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ public Task<string> DataAsync(int tenantId, string entryId)
return FileQueries.DataAsync(this, tenantId, entryId);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null])]
public IAsyncEnumerable<DbFilesProperties> FilesPropertiesAsync(int tenantId, IEnumerable<string> filesIds)
{
return FileQueries.FilesPropertiesAsync(this, tenantId, filesIds);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null])]
public Task<int> DeleteFilesPropertiesAsync(int tenantId, string entryId)
{
Expand Down Expand Up @@ -830,6 +836,13 @@ select f
.Where(r => r.EntryId == entryId)
.Select(r => r.Data)
.FirstOrDefault());

public static readonly Func<FilesDbContext, int, IEnumerable<string>, IAsyncEnumerable<DbFilesProperties>> FilesPropertiesAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<string> filesIds) =>
ctx.FilesProperties
.Where(r => r.TenantId == tenantId)
.Where(r => filesIds.Contains(r.EntryId)));

public static readonly Func<FilesDbContext, int, string, Task<int>> DeleteFilesPropertiesAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
Expand Down
13 changes: 13 additions & 0 deletions products/ASC.Files/Core/Core/EF/Queries/LinkQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public Task<string> LinkedIdAsync(int tenantId, string sourceId, Guid id)
return LinkQueries.LinkedIdAsync(this, tenantId, sourceId, id);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null, PreCompileQuery.DefaultGuid])]
public IAsyncEnumerable<DbFilesLink> FilesLinksAsync(int tenantId, IEnumerable<string> sourceIds, Guid id)
{
return LinkQueries.FilesLinksAsync(this, tenantId, sourceIds, id);
}

[PreCompileQuery([PreCompileQuery.DefaultInt, null, PreCompileQuery.DefaultGuid])]
public Task<DbFilesLink> FileLinkAsync(int tenantId, string sourceId, Guid id)
Expand Down Expand Up @@ -73,6 +78,14 @@ static file class LinkQueries
.OrderByDescending(r => r)
.LastOrDefault());

public static readonly Func<FilesDbContext, int, IEnumerable<string>, Guid, IAsyncEnumerable<DbFilesLink>> FilesLinksAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, IEnumerable<string> sourceIds, Guid id) =>
ctx.FilesLink
.Where(r => r.TenantId == tenantId && sourceIds.Contains(r.SourceId) && r.LinkedFor == id)
.GroupBy(r => r.SourceId)
.Select(g => g.OrderByDescending(r => r.LinkedId).LastOrDefault()));

public static readonly Func<FilesDbContext, int, string, Guid, Task<DbFilesLink>> FileLinkAsync =
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery(
(FilesDbContext ctx, int tenantId, string sourceId, Guid id) =>
Expand Down
8 changes: 8 additions & 0 deletions products/ASC.Files/Core/Core/Entries/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,12 @@ public string ConvertedExtension
}

public DateTime? LastOpened { get; set; }
public FormInfo<T> FormInfo { get; set; }
}

public record FormInfo<T>
{
public T LinkedId { get; init; }
public EntryProperties<T> Properties { get; init; }
public static FormInfo<T> Empty => new();
}
28 changes: 21 additions & 7 deletions products/ASC.Files/Core/Core/FileStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,8 @@ private async Task<Folder<T>> InternalCreateFolderAsync<T>(T parentId, string ti
var tags = tagsInfos.Select(tagInfo => Tag.Custom(Guid.Empty, folder, tagInfo.Name));

await tagDao.SaveTagsAsync(tags);

await filesMessageService.SendAsync(MessageAction.AddedRoomTags, folder, folder.Title, string.Join(',', tags.Select(x => x.Name)));
}
}

Expand Down Expand Up @@ -920,12 +922,7 @@ await filesMessageService.SendAsync(updateData.DenyDownload.Value
folder, folder.Title);
}

if (colorChanged)
{
await filesMessageService.SendAsync(MessageAction.RoomColorChanged, folder, folder.Title);
}

if (coverChanged)
if ((colorChanged || coverChanged) && !folder.SettingsHasLogo)
{
await filesMessageService.SendAsync(MessageAction.RoomCoverChanged, folder, folder.Title);
}
Expand Down Expand Up @@ -1001,11 +998,22 @@ await filesMessageService.SendAsync(MessageAction.RoomLifeTimeSet, folder, lifet
var tags = tagsInfos.Select(tagInfo => Tag.Custom(Guid.Empty, folder, tagInfo.Name));

await tagDao.SaveTagsAsync(tags);

var addedTags = tags.Select(t => t.Name).Except(currentTags.Select(t => t.Name)).ToList();
if (addedTags.Count > 0)
{
await filesMessageService.SendAsync(MessageAction.AddedRoomTags, folder, folder.Title, string.Join(',', addedTags));
}
}
}

var toDelete = currentTags.Where(r => tagsInfos.All(b => b.Name != r.Name)).ToList();
await tagDao.RemoveTagsAsync(folder, toDelete.Select(t => t.Id).ToList());

if (toDelete.Count > 0)
{
await filesMessageService.SendAsync(MessageAction.DeletedRoomTags, folder, folder.Title, string.Join(',', toDelete.Select(t => t.Name)));
}
}

var newTags = tagDao.GetNewTagsAsync(authContext.CurrentAccount.ID, folder);
Expand Down Expand Up @@ -1648,8 +1656,14 @@ public async IAsyncEnumerable<File<T>> GetFileHistoryAsync<T>(T fileId)
{
throw new InvalidOperationException(FilesCommonResource.ErrorMessage_SecurityException_ReadFile);
}

var history = await fileDao.GetFileHistoryAsync(fileId).ToListAsync();

var t1 = entryStatusManager.SetFileStatusAsync(history);
var t2 = entryStatusManager.SetFormInfoAsync(history);
await Task.WhenAll(t1, t2);

await foreach (var r in fileDao.GetFileHistoryAsync(fileId))
foreach (var r in history)
{
await entryStatusManager.SetFileStatusAsync(r);
yield return r;
Expand Down
4 changes: 2 additions & 2 deletions products/ASC.Files/Core/Core/History/ActionInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public async ValueTask<HistoryEntry> InterpretAsync(DbAuditEvent @event, FileEnt
var initiatorId = @event.UserId ?? ASC.Core.Configuration.Constants.Guest.ID;
string initiatorName = null;

if (!string.IsNullOrEmpty(data?.InitiatorName))
if (!string.IsNullOrEmpty(data?.InitiatorName) && initiatorId == ASC.Core.Configuration.Constants.Guest.ID)
{
initiatorName = initiatorId == ASC.Core.Configuration.Constants.Guest.ID && data.InitiatorName != AuditReportResource.GuestAccount
initiatorName = data.InitiatorName != AuditReportResource.GuestAccount
? $"{data.InitiatorName} ({FilesCommonResource.ExternalUser})"
: data.InitiatorName;
}
Expand Down
4 changes: 4 additions & 0 deletions products/ASC.Files/Core/Core/Security/ExternalShare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ public class ValidationInfo
/// <summary>Link ID</summary>
/// <type>System.Guid, System</type>
public Guid LinkId { get; set; }

/// <summary>Specifies whether the user is authenticated or not</summary>
/// <type>System.Boolean, System</type>
public bool IsAuthenticated { get; set; }
}

public record DownloadSession
Expand Down
5 changes: 5 additions & 0 deletions products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,11 @@ public Task<EntryProperties<string>> GetProperties(string fileId)
return Task.FromResult<EntryProperties<string>>(null);
}

public Task<Dictionary<string, EntryProperties<string>>> GetPropertiesAsync(IEnumerable<string> filesIds)
{
return Task.FromResult<Dictionary<string, EntryProperties<string>>>(null);
}

public Task SaveProperties(string fileId, EntryProperties<string> entryProperties)
{
return Task.CompletedTask;
Expand Down
Loading

0 comments on commit e9d6a36

Please sign in to comment.