Merge branch 'master' into feature/files
This commit is contained in:
commit
de55454c84
@ -50,6 +50,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Files", "products\ASC.F
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppLimit.CloudComputing.SharpBox", "thirdparty\AppLimit.CloudComputing.SharpBox\AppLimit.CloudComputing.SharpBox.csproj", "{5B53855C-4347-4402-B750-76C6295A35D3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Files.Service", "products\ASC.Files\Service\ASC.Files.Service.csproj", "{5D41FFFF-816C-40B2-95CD-E2DDDCB83784}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -144,6 +146,10 @@ Global
|
||||
{5B53855C-4347-4402-B750-76C6295A35D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5B53855C-4347-4402-B750-76C6295A35D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5B53855C-4347-4402-B750-76C6295A35D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5D41FFFF-816C-40B2-95CD-E2DDDCB83784}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D41FFFF-816C-40B2-95CD-E2DDDCB83784}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D41FFFF-816C-40B2-95CD-E2DDDCB83784}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5D41FFFF-816C-40B2-95CD-E2DDDCB83784}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
2
build/run/FileService.bat
Normal file
2
build/run/FileService.bat
Normal file
@ -0,0 +1,2 @@
|
||||
echo "RUN ASC.Files"
|
||||
call dotnet run --project ..\..\products\ASC.Files\Service\ASC.Files.Service.csproj --no-build --$STORAGE_ROOT=..\..\..\Data --log__dir=..\..\..\Logs --log__name=files
|
@ -12,8 +12,6 @@ using Confluent.Kafka;
|
||||
using Google.Protobuf;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Common.Caching
|
||||
|
@ -26,7 +26,7 @@ namespace ASC.Common.DependencyInjection
|
||||
|
||||
public static class AutofacExtension
|
||||
{
|
||||
public static IContainer AddAutofac(this IServiceCollection services, IConfiguration configuration, string currentDir)
|
||||
public static IContainer AddAutofac(this IServiceCollection services, IConfiguration configuration, string currentDir, params string[] intern)
|
||||
{
|
||||
var folder = configuration["core:products:folder"];
|
||||
var subfolder = configuration["core:products:subfolder"];
|
||||
@ -42,19 +42,32 @@ namespace ASC.Common.DependencyInjection
|
||||
}
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
var modules = new string[] { "autofac.json", "autofac.products.json", "autofac.consumers.json" };
|
||||
var modules = new List<(bool, string)>
|
||||
{
|
||||
(true, "autofac.json"),
|
||||
(true, "autofac.products.json"),
|
||||
(true, "autofac.consumers.json")
|
||||
};
|
||||
|
||||
if (intern != null)
|
||||
{
|
||||
modules.AddRange(intern.Select(r => (false, r)));
|
||||
}
|
||||
|
||||
foreach (var p in modules)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(configuration["pathToConf"])
|
||||
.AddJsonFile(p);
|
||||
var config = new ConfigurationBuilder();
|
||||
if (p.Item1)
|
||||
{
|
||||
config.SetBasePath(configuration["pathToConf"]);
|
||||
}
|
||||
config.AddJsonFile(p.Item2);
|
||||
|
||||
var root = config.Build();
|
||||
var module = new ConfigurationModule(root);
|
||||
builder.RegisterModule(module);
|
||||
|
||||
if (p == "autofac.products.json")
|
||||
if (p.Item2 == "autofac.products.json")
|
||||
{
|
||||
FindAndLoad(root.GetSection("components"));
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
@ -35,7 +35,6 @@ using log4net.Config;
|
||||
using log4net.Core;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using NLog;
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ASC.Common.Utils
|
||||
|
@ -30,8 +30,6 @@ using System.Text;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ASC.Common.Utils
|
||||
|
@ -35,7 +35,6 @@ using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Caching
|
||||
|
@ -33,8 +33,6 @@ using ASC.Common.Utils;
|
||||
using ASC.Core.Common.EF.Context;
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Caching
|
||||
|
@ -36,8 +36,6 @@ using ASC.Core.Common.EF;
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Caching
|
||||
|
@ -377,6 +377,11 @@ namespace ASC.Core.Common.Configuration
|
||||
public ConsumerFactory(IContainer builder)
|
||||
{
|
||||
Builder = builder.BeginLifetimeScope();
|
||||
}
|
||||
|
||||
public ConsumerFactory(ILifetimeScope builder)
|
||||
{
|
||||
Builder = builder;
|
||||
}
|
||||
|
||||
public Consumer GetByKey(string key)
|
||||
|
@ -389,7 +389,8 @@ namespace ASC.Core
|
||||
public static DIHelper AddCoreConfigurationService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<CoreConfiguration>();
|
||||
return services
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
.AddCoreSettingsService();
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,6 @@ namespace ASC.Core
|
||||
ITenantService tenantService,
|
||||
IQuotaService quotaService,
|
||||
ITariffService tariffService,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings)
|
||||
{
|
||||
@ -137,6 +136,16 @@ namespace ASC.Core
|
||||
TariffService = tariffService;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
CoreSettings = coreSettings;
|
||||
}
|
||||
|
||||
public TenantManager(
|
||||
ITenantService tenantService,
|
||||
IQuotaService quotaService,
|
||||
ITariffService tariffService,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings) : this(tenantService, quotaService, tariffService, coreBaseSettings, coreSettings)
|
||||
{
|
||||
HttpContext = httpContextAccessor?.HttpContext;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,6 @@ namespace ASC.Core
|
||||
private IHttpContextAccessor HttpContextAccessor { get; }
|
||||
|
||||
public SecurityContext(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
UserManager userManager,
|
||||
AuthManager authentication,
|
||||
AuthContext authContext,
|
||||
@ -95,6 +94,20 @@ namespace ASC.Core
|
||||
UserFormatter = userFormatter;
|
||||
CookieStorage = cookieStorage;
|
||||
TenantCookieSettingsHelper = tenantCookieSettingsHelper;
|
||||
}
|
||||
|
||||
public SecurityContext(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
UserManager userManager,
|
||||
AuthManager authentication,
|
||||
AuthContext authContext,
|
||||
TenantManager tenantManager,
|
||||
UserFormatter userFormatter,
|
||||
CookieStorage cookieStorage,
|
||||
TenantCookieSettingsHelper tenantCookieSettingsHelper,
|
||||
IOptionsMonitor<ILog> options
|
||||
) : this(userManager, authentication, authContext, tenantManager, userFormatter, cookieStorage, tenantCookieSettingsHelper, options)
|
||||
{
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Common.EF
|
||||
@ -79,7 +79,7 @@ namespace ASC.Core.Common.EF
|
||||
services.TryAddScoped<IConfigureOptions<MultiRegionalDbContext<T>>, ConfigureMultiRegionalDbContext<T>>();
|
||||
//services.TryAddScoped<T>();
|
||||
|
||||
return services;
|
||||
return services.AddLoggerService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,7 @@ namespace ASC.Core.Common.EF.Context
|
||||
|
||||
modelBuilder.AddCoreSettings();
|
||||
|
||||
modelBuilder.Entity<DbTenant>()
|
||||
.HasOne(r => r.Partner)
|
||||
.WithOne(r => r.Tenant)
|
||||
.HasForeignKey<DbTenantPartner>(r => new { r.TenantId })
|
||||
.HasPrincipalKey<DbTenant>(r => new { r.Id });
|
||||
modelBuilder.AddDbTenant();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace ASC.Core.Common.EF.Model
|
||||
{
|
||||
[Table("webstudio_index")]
|
||||
public class DbWebstudioIndex
|
||||
public class DbWebstudioIndex : BaseEntity
|
||||
{
|
||||
[Key]
|
||||
[Column("index_name")]
|
||||
@ -13,5 +13,7 @@ namespace ASC.Core.Common.EF.Model
|
||||
|
||||
[Column("last_modified")]
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public override object[] GetKeys() => new[] { IndexName };
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ASC.Core.Common.EF.Model
|
||||
{
|
||||
[Table("tenants_tenants")]
|
||||
@ -39,4 +42,16 @@ namespace ASC.Core.Common.EF.Model
|
||||
|
||||
public DbTenantPartner Partner { get; set; }
|
||||
}
|
||||
|
||||
public static class DbTenantExtension
|
||||
{
|
||||
public static void AddDbTenant(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<DbTenant>()
|
||||
.HasOne(r => r.Partner)
|
||||
.WithOne(r => r.Tenant)
|
||||
.HasForeignKey<DbTenantPartner>(r => new { r.TenantId })
|
||||
.HasPrincipalKey<DbTenant>(r => new { r.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ using System.Linq;
|
||||
using ASC.Common;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Notify.Recipients;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ASC.Core.Notify
|
||||
{
|
||||
|
@ -48,17 +48,25 @@ namespace ASC.Core.Security.Authentication
|
||||
private ILog Log { get; }
|
||||
|
||||
public CookieStorage(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
InstanceCrypto instanceCrypto,
|
||||
TenantCookieSettingsHelper tenantCookieSettingsHelper,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
InstanceCrypto = instanceCrypto;
|
||||
TenantCookieSettingsHelper = tenantCookieSettingsHelper;
|
||||
HttpContext = httpContextAccessor.HttpContext;
|
||||
Log = options.CurrentValue;
|
||||
}
|
||||
|
||||
public CookieStorage(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
InstanceCrypto instanceCrypto,
|
||||
TenantCookieSettingsHelper tenantCookieSettingsHelper,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: this(instanceCrypto, tenantCookieSettingsHelper, options)
|
||||
{
|
||||
HttpContext = httpContextAccessor.HttpContext;
|
||||
}
|
||||
|
||||
public bool DecryptCookie(string cookie, out int tenant, out Guid userid, out string login, out string password, out int indexTenant, out DateTime expire, out int indexUser)
|
||||
{
|
||||
tenant = Tenant.DEFAULT_TENANT;
|
||||
|
@ -27,8 +27,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ASC.Core.Security.Authorizing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ASC.Common.Security.Authorizing
|
||||
{
|
||||
|
@ -31,8 +31,6 @@ using System.Linq;
|
||||
using ASC.Common;
|
||||
using ASC.Common.Security;
|
||||
using ASC.Common.Security.Authorizing;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ASC.Core.Security.Authorizing
|
||||
{
|
||||
|
@ -33,8 +33,6 @@ using ASC.Common.Security;
|
||||
using ASC.Common.Security.Authentication;
|
||||
using ASC.Common.Security.Authorizing;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
using Constants = ASC.Core.Configuration.Constants;
|
||||
|
||||
namespace ASC.Core.Security.Authorizing
|
||||
|
@ -35,7 +35,6 @@ using ASC.Common.Security.Authorizing;
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ASC.Core.Security.Authorizing
|
||||
{
|
||||
|
@ -57,7 +57,9 @@ namespace ASC.Core.Common.Settings
|
||||
{
|
||||
services.TryAddScoped<SettingsManager>();
|
||||
|
||||
return services.AddDbSettingsManagerService();
|
||||
return services
|
||||
.AddAuthContextService()
|
||||
.AddDbSettingsManagerService();
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ using ASC.Common.Threading.Progress;
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Data.Reassigns
|
||||
|
@ -7,7 +7,6 @@ using ASC.Common.Utils;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ASC.Data.Storage.Configuration
|
||||
{
|
||||
|
@ -133,7 +133,6 @@ namespace ASC.Data.Storage.Configuration
|
||||
IOptionsMonitor<ILog> options,
|
||||
TenantManager tenantManager,
|
||||
SettingsManager settingsManager,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ConsumerFactory consumerFactory)
|
||||
{
|
||||
BaseStorageSettingsListener = baseStorageSettingsListener;
|
||||
@ -144,9 +143,23 @@ namespace ASC.Data.Storage.Configuration
|
||||
Options = options;
|
||||
TenantManager = tenantManager;
|
||||
SettingsManager = settingsManager;
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
ConsumerFactory = consumerFactory;
|
||||
}
|
||||
public StorageSettingsHelper(
|
||||
BaseStorageSettingsListener baseStorageSettingsListener,
|
||||
StorageFactoryConfig storageFactoryConfig,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
ICacheNotify<DataStoreCacheItem> cache,
|
||||
IOptionsMonitor<ILog> options,
|
||||
TenantManager tenantManager,
|
||||
SettingsManager settingsManager,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ConsumerFactory consumerFactory)
|
||||
: this(baseStorageSettingsListener, storageFactoryConfig, pathUtils, emailValidationKeyProvider, cache, options, tenantManager, settingsManager, consumerFactory)
|
||||
{
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public bool Save<T>(BaseStorageSettings<T> baseStorageSettings) where T : class, ISettings, new()
|
||||
{
|
||||
|
@ -159,7 +159,6 @@ namespace ASC.Data.Storage
|
||||
StaticUploader staticUploader,
|
||||
SettingsManager settingsManager,
|
||||
StorageSettingsHelper storageSettingsHelper,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IHostEnvironment hostEnvironment,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
IOptionsMonitor<ILog> options)
|
||||
@ -168,12 +167,25 @@ namespace ASC.Data.Storage
|
||||
StaticUploader = staticUploader;
|
||||
SettingsManager = settingsManager;
|
||||
StorageSettingsHelper = storageSettingsHelper;
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
HostEnvironment = hostEnvironment;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public WebPath(
|
||||
WebPathSettings webPathSettings,
|
||||
StaticUploader staticUploader,
|
||||
SettingsManager settingsManager,
|
||||
StorageSettingsHelper storageSettingsHelper,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IHostEnvironment hostEnvironment,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: this(webPathSettings, staticUploader, settingsManager, storageSettingsHelper, hostEnvironment, coreBaseSettings, options)
|
||||
{
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string GetPath(string relativePath)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(relativePath) && relativePath.IndexOf('~') == 0)
|
||||
@ -194,7 +206,7 @@ namespace ASC.Data.Storage
|
||||
}
|
||||
}
|
||||
|
||||
return WebPathSettings.GetPath(HttpContextAccessor.HttpContext, Options, relativePath);
|
||||
return WebPathSettings.GetPath(HttpContextAccessor?.HttpContext, Options, relativePath);
|
||||
}
|
||||
|
||||
public bool Exists(string relativePath)
|
||||
|
@ -48,7 +48,6 @@ namespace ASC.MessagingSystem
|
||||
|
||||
public MessageService(
|
||||
IConfiguration configuration,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
MessageFactory messageFactory,
|
||||
DbMessageSender sender,
|
||||
MessagePolicy messagePolicy,
|
||||
@ -61,11 +60,22 @@ namespace ASC.MessagingSystem
|
||||
|
||||
this.sender = sender;
|
||||
MessagePolicy = messagePolicy;
|
||||
request = httpContextAccessor?.HttpContext?.Request;
|
||||
MessageFactory = messageFactory;
|
||||
log = options.CurrentValue;
|
||||
}
|
||||
|
||||
public MessageService(
|
||||
IConfiguration configuration,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
MessageFactory messageFactory,
|
||||
DbMessageSender sender,
|
||||
MessagePolicy messagePolicy,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: this(configuration, messageFactory, sender, messagePolicy, options)
|
||||
{
|
||||
request = httpContextAccessor?.HttpContext?.Request;
|
||||
}
|
||||
|
||||
#region HttpRequest
|
||||
|
||||
public void Send(MessageAction action)
|
||||
|
@ -22,12 +22,12 @@
|
||||
<None Remove="protos\SearchItem.proto" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Elasticsearch.Net" Version="6.5.0" />
|
||||
<PackageReference Include="Elasticsearch.Net" Version="7.6.1" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.27.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NEST" Version="6.5.0" />
|
||||
<PackageReference Include="NEST" Version="7.6.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
|
||||
|
@ -28,90 +28,6 @@ using System;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnAttribute : Attribute
|
||||
{
|
||||
public string ColumnName { get; private set; }
|
||||
|
||||
public ColumnTypeEnum ColumnType { get; private set; }
|
||||
|
||||
public int Order { get; private set; }
|
||||
|
||||
public Analyzer Analyzer { get; set; }
|
||||
|
||||
public Filter Filter { get; set; }
|
||||
|
||||
public CharFilter CharFilter { get; set; }
|
||||
|
||||
public ColumnAttribute(string columnName, int order, ColumnTypeEnum columnType = ColumnTypeEnum.Content, Filter filter = Filter.lowercase, CharFilter charFilter = CharFilter.io)
|
||||
{
|
||||
ColumnName = columnName;
|
||||
ColumnType = columnType;
|
||||
Order = order;
|
||||
Analyzer = Analyzer.whitespace;
|
||||
Filter = filter;
|
||||
CharFilter = charFilter;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnIdAttribute : ColumnAttribute
|
||||
{
|
||||
public ColumnIdAttribute(string columnName)
|
||||
: base(columnName, -3, ColumnTypeEnum.Id)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnTenantIdAttribute : ColumnAttribute
|
||||
{
|
||||
public ColumnTenantIdAttribute(string columnName)
|
||||
: base(columnName, -2, ColumnTypeEnum.TenantId)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnLastModifiedAttribute : ColumnAttribute
|
||||
{
|
||||
public ColumnLastModifiedAttribute(string columnName)
|
||||
: base(columnName, -1, ColumnTypeEnum.LastModified)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnConditionAttribute : ColumnAttribute
|
||||
{
|
||||
internal object Value { get; private set; }
|
||||
public ColumnConditionAttribute(string columnName, int order, object value = null)
|
||||
: base(columnName, order, ColumnTypeEnum.Condition)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ColumnMeta : ColumnAttribute
|
||||
{
|
||||
public ColumnMeta(string columnName, int order)
|
||||
: base(columnName, order, ColumnTypeEnum.Meta)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public enum ColumnTypeEnum
|
||||
{
|
||||
Id,
|
||||
TenantId,
|
||||
LastModified,
|
||||
Content,
|
||||
Condition,
|
||||
Meta
|
||||
}
|
||||
|
||||
public enum Analyzer
|
||||
{
|
||||
standard,
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public class JoinAttribute : Attribute
|
||||
{
|
||||
public JoinTypeEnum JoinType { get; private set; }
|
||||
public string[] ColumnsFrom { get; private set; }
|
||||
public string[] ColumnsTo { get; private set; }
|
||||
|
||||
public JoinAttribute(JoinTypeEnum joinType, params string[] columns)
|
||||
{
|
||||
JoinType = joinType;
|
||||
ColumnsFrom = new string[columns.Length];
|
||||
ColumnsTo = new string[columns.Length];
|
||||
|
||||
for (var i = 0; i< columns.Length; i++)
|
||||
{
|
||||
var column = columns[i].Split(':');
|
||||
ColumnsFrom[i] = column[0];
|
||||
ColumnsTo[i] = column[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum JoinTypeEnum
|
||||
{
|
||||
Inner,
|
||||
Sub
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace ASC.ElasticSearch.Config
|
||||
{
|
||||
class ElasticSection : ConfigurationSection
|
||||
{
|
||||
[ConfigurationProperty("host", IsRequired = true, DefaultValue = "localhost")]
|
||||
public string Host
|
||||
{
|
||||
get { return (string)this["host"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("port", IsRequired = false, DefaultValue = "9200")]
|
||||
public int Port
|
||||
{
|
||||
get { return Convert.ToInt32(this["port"]); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("scheme", IsRequired = false, DefaultValue = "http")]
|
||||
public string Scheme
|
||||
{
|
||||
get { return (string)this["scheme"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("period", IsRequired = false, DefaultValue = 1)]
|
||||
public int Period
|
||||
{
|
||||
get { return Convert.ToInt32(this["period"]); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("memoryLimit", IsRequired = false, DefaultValue = 10 * 1024 * 1024L)]
|
||||
public long MemoryLimit
|
||||
{
|
||||
get { return Convert.ToInt64(this["memoryLimit"]); }
|
||||
}
|
||||
}
|
||||
}
|
19
common/services/ASC.ElasticSearch/Core/ISearchItem.cs
Normal file
19
common/services/ASC.ElasticSearch/Core/ISearchItem.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
public interface ISearchItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int TenantId { get; set; }
|
||||
public string IndexName { get; }
|
||||
|
||||
public Expression<Func<ISearchItem, object[]>> SearchContentFields { get; }
|
||||
}
|
||||
|
||||
public interface ISearchItemDocument : ISearchItem
|
||||
{
|
||||
public Document Document { get; set; }
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.Settings;
|
||||
|
||||
@ -82,21 +83,27 @@ namespace ASC.ElasticSearch.Core
|
||||
}
|
||||
|
||||
public class SearchSettingsHelper
|
||||
{
|
||||
{
|
||||
public TenantManager TenantManager { get; }
|
||||
public SettingsManager SettingsManager { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
public FactoryIndexer FactoryIndexer { get; }
|
||||
public FactoryIndexer FactoryIndexer { get; }
|
||||
public ICacheNotify<ReIndexAction> CacheNotify { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public SearchSettingsHelper(
|
||||
public SearchSettingsHelper(
|
||||
TenantManager tenantManager,
|
||||
SettingsManager settingsManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
FactoryIndexer factoryIndexer,
|
||||
FactoryIndexer factoryIndexer,
|
||||
ICacheNotify<ReIndexAction> cacheNotify,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
{
|
||||
TenantManager = tenantManager;
|
||||
SettingsManager = settingsManager;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
FactoryIndexer = factoryIndexer;
|
||||
FactoryIndexer = factoryIndexer;
|
||||
CacheNotify = cacheNotify;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
@ -114,14 +121,12 @@ namespace ASC.ElasticSearch.Core
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private List<WrapperWithDoc> allItems;
|
||||
internal List<WrapperWithDoc> AllItems
|
||||
private List<IFactoryIndexer> allItems;
|
||||
internal List<IFactoryIndexer> AllItems
|
||||
{
|
||||
get
|
||||
{
|
||||
return allItems ?? (allItems = FactoryIndexer.Builder.Resolve<IEnumerable<Wrapper>>()
|
||||
.OfType<WrapperWithDoc>()
|
||||
.ToList());
|
||||
return allItems ?? (allItems = FactoryIndexer.Builder.Resolve<IEnumerable<IFactoryIndexer>>().ToList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,19 +142,18 @@ namespace ASC.ElasticSearch.Core
|
||||
settings.Items = items;
|
||||
settings.Data = JsonConvert.SerializeObject(items);
|
||||
SettingsManager.Save(settings);
|
||||
|
||||
//TODO:
|
||||
//using (var service = new ServiceClient())
|
||||
//{
|
||||
// service.ReIndex(toReIndex.Select(r => r.ID).ToList(), TenantManager.GetCurrentTenant().TenantId);
|
||||
//}
|
||||
|
||||
var action = new ReIndexAction() { Tenant = TenantManager.GetCurrentTenant().TenantId };
|
||||
action.Names.AddRange(toReIndex.Select(r => r.ID).ToList());
|
||||
|
||||
CacheNotify.Publish(action, CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
public bool CanSearchByContent<T>(int tenantId) where T : Wrapper
|
||||
public bool CanSearchByContent<T>(int tenantId) where T : class, ISearchItem
|
||||
{
|
||||
if (!SearchByContentEnabled) return false;
|
||||
|
||||
if (!typeof(T).IsSubclassOf(typeof(WrapperWithDoc)))
|
||||
|
||||
if (typeof(ISearchItemDocument).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -190,7 +194,8 @@ namespace ASC.ElasticSearch.Core
|
||||
return services
|
||||
.AddSettingsManagerService()
|
||||
.AddCoreBaseSettingsService()
|
||||
.AddFactoryIndexerService();
|
||||
.AddFactoryIndexerService()
|
||||
.AddTenantManagerService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Nest;
|
||||
using Nest;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
public class Selector<T> where T : Wrapper
|
||||
public class Selector<T> where T : class, ISearchItem
|
||||
{
|
||||
private readonly QueryContainerDescriptor<T> queryContainerDescriptor = new QueryContainerDescriptor<T>();
|
||||
private SortDescriptor<T> sortContainerDescriptor = new SortDescriptor<T>();
|
||||
@ -120,11 +120,11 @@ namespace ASC.ElasticSearch
|
||||
|
||||
if (IsExactlyPhrase(value))
|
||||
{
|
||||
queryContainer = queryContainer & Wrap(selector, (a, w) => w.MatchPhrase(r => r.Field(a).Query(value.TrimQuotes())));
|
||||
queryContainer &= Wrap(selector, (a, w) => w.MatchPhrase(r => r.Field(a).Query(value.TrimQuotes())));
|
||||
}
|
||||
else if (value.HasOtherLetter() || IsExactly(value))
|
||||
{
|
||||
queryContainer = queryContainer & Wrap(selector, (a, w) => w.Match(r => r.Field(a).Query(value.TrimQuotes())));
|
||||
queryContainer &= Wrap(selector, (a, w) => w.Match(r => r.Field(a).Query(value.TrimQuotes())));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -134,19 +134,19 @@ namespace ASC.ElasticSearch
|
||||
foreach (var p in phrase)
|
||||
{
|
||||
var p1 = p;
|
||||
queryContainer = queryContainer & Wrap(selector, (a, w) => w.Wildcard(r => r.Field(a).Value(p1.WrapAsterisk())));
|
||||
queryContainer &= Wrap(selector, (a, w) => w.Wildcard(r => r.Field(a).Value(p1.WrapAsterisk())));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
queryContainer = queryContainer & Wrap(selector, (a, w) => w.Wildcard(r => r.Field(a).Value(value.WrapAsterisk())));
|
||||
queryContainer &= Wrap(selector, (a, w) => w.Wildcard(r => r.Field(a).Value(value.WrapAsterisk())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (IsExactly(value))
|
||||
{
|
||||
queryContainer = queryContainer | Wrap(selector, (a, w) => w.MatchPhrase(r => r.Field(a).Query(value)));
|
||||
queryContainer |= Wrap(selector, (a, w) => w.MatchPhrase(r => r.Field(a).Query(value)));
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -199,7 +199,7 @@ namespace ASC.ElasticSearch
|
||||
|
||||
public Selector<T> MatchAll(string value)
|
||||
{
|
||||
Match(() => ServiceProvider.GetService<T>().GetContentProperties(), value);
|
||||
Match(() => ((NewArrayExpression)(ServiceProvider.GetService<T>().SearchContentFields).Body).Expressions.ToArray(), value);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -331,7 +331,6 @@ namespace ASC.ElasticSearch
|
||||
|
||||
if (string.IsNullOrEmpty(path) &&
|
||||
!string.IsNullOrEmpty(fieldSelector.Name) &&
|
||||
fieldSelector.Name.StartsWith(JoinTypeEnum.Sub + ":") &&
|
||||
fieldSelector.Name.IndexOf(".", StringComparison.InvariantCulture) > 0)
|
||||
{
|
||||
var splitted = fieldSelector.Name.Split(':')[1];
|
||||
|
@ -1,370 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ASC.ElasticSearch.Core;
|
||||
using Nest;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
public abstract class Wrapper
|
||||
{
|
||||
protected internal abstract string Table { get; }
|
||||
|
||||
protected internal virtual string IndexName
|
||||
{
|
||||
get { return Table; }
|
||||
}
|
||||
|
||||
[ColumnId("id")]
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
[ColumnTenantId("tenant_id")]
|
||||
public virtual int TenantId { get; set; }
|
||||
|
||||
[ColumnLastModified("last_modified_on"), Date]
|
||||
public virtual DateTime LastModifiedOn { get; set; }
|
||||
|
||||
private List<PropertyInfo> orderedProperties;
|
||||
|
||||
private List<PropertyInfo> OrderedProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return orderedProperties ?? (orderedProperties = GetType()
|
||||
.GetProperties()
|
||||
.Where(r =>
|
||||
{
|
||||
var column = r.GetCustomAttribute<ColumnAttribute>();
|
||||
return column != null && !string.IsNullOrEmpty(column.ColumnName);
|
||||
})
|
||||
.OrderBy(r => r.GetCustomAttribute<ColumnAttribute>().Order)
|
||||
.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
private List<ColumnAttribute> columns;
|
||||
|
||||
private List<ColumnAttribute> Columns
|
||||
{
|
||||
get
|
||||
{
|
||||
return columns ?? (columns = OrderedProperties
|
||||
.Select(r => r.GetCustomAttribute<ColumnAttribute>())
|
||||
.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
internal Converter<object[], Wrapper> GetDataConverter(bool sub = false)
|
||||
{
|
||||
return data =>
|
||||
{
|
||||
var result = Activator.CreateInstance(GetType());
|
||||
|
||||
var i = 0;
|
||||
var props = OrderedProperties;
|
||||
for (; i < props.Count; i++)
|
||||
{
|
||||
if (data[i] == null) continue;
|
||||
object newValue;
|
||||
if (props[i].PropertyType == typeof(Guid))
|
||||
{
|
||||
newValue = Guid.Parse(data[i].ToString());
|
||||
}
|
||||
else if (props[i].PropertyType == typeof(bool))
|
||||
{
|
||||
try
|
||||
{
|
||||
newValue = Convert.ToBoolean(data[i]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
newValue = data[i] != null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
newValue = Convert.ChangeType(data[i], props[i].PropertyType);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
newValue = Activator.CreateInstance(props[i].PropertyType);
|
||||
}
|
||||
}
|
||||
props[i].SetValue(result, newValue);
|
||||
}
|
||||
|
||||
var joins = GetType()
|
||||
.GetProperties()
|
||||
.Where(r => r.GetCustomAttribute<JoinAttribute>() != null)
|
||||
.ToList();
|
||||
|
||||
if (!joins.Any()) return (Wrapper) result;
|
||||
|
||||
data = data.Skip(i).ToArray();
|
||||
|
||||
foreach (var join in joins)
|
||||
{
|
||||
Wrapper joinWrapper;
|
||||
|
||||
if (join.PropertyType.IsGenericType)
|
||||
{
|
||||
joinWrapper = Activator.CreateInstance(join.PropertyType.GenericTypeArguments[0]) as Wrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
joinWrapper = Activator.CreateInstance(join.PropertyType) as Wrapper;
|
||||
}
|
||||
|
||||
if (joinWrapper == null) continue;
|
||||
|
||||
var joinAttr = join.GetCustomAttribute<JoinAttribute>();
|
||||
var joinSub = sub || joinAttr.JoinType == JoinTypeEnum.Sub;
|
||||
List<object[]> newArray;
|
||||
if (joinSub && join.PropertyType.IsGenericType)
|
||||
{
|
||||
newArray = data[0] == null
|
||||
? new List<object[]>()
|
||||
: JArray.Parse(data[0].ToString()).Select(r => ((JArray)r).Select(q => (object)q).ToArray()).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
newArray = new List<object[]> {data};
|
||||
}
|
||||
|
||||
var newArrayValue = newArray.ConvertAll(joinWrapper.GetDataConverter(joinSub));
|
||||
|
||||
object newValue;
|
||||
|
||||
if (joinSub && join.PropertyType.IsGenericType)
|
||||
{
|
||||
var list = (IList)Activator.CreateInstance(join.PropertyType);
|
||||
foreach (var item in newArrayValue)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
newValue = list;
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = Convert.ChangeType(newArrayValue.First(), join.PropertyType);
|
||||
}
|
||||
|
||||
join.SetValue(result, newValue);
|
||||
|
||||
var skipCount = joinSub
|
||||
? 1
|
||||
: joinWrapper.OrderedProperties.Count;
|
||||
|
||||
data = data.Skip(skipCount).ToArray();
|
||||
}
|
||||
|
||||
return (Wrapper) result;
|
||||
};
|
||||
}
|
||||
|
||||
internal string GetColumnName(ColumnTypeEnum columnType, string alias)
|
||||
{
|
||||
var column = Columns.FirstOrDefault(r => r.ColumnType == columnType);
|
||||
if (column == null || string.IsNullOrEmpty(column.ColumnName)) return null;
|
||||
return alias + "." + column.ColumnName;
|
||||
}
|
||||
|
||||
internal bool TryGetColumnName(ColumnTypeEnum columnType, string alias, out string columnName)
|
||||
{
|
||||
columnName = GetColumnName(columnType, alias);
|
||||
return columnName != null;
|
||||
}
|
||||
|
||||
internal bool TryGetColumnNames(List<ColumnTypeEnum> columnType, string alias, out List<string> columnName)
|
||||
{
|
||||
columnName = new List<string>();
|
||||
foreach (var cType in columnType)
|
||||
{
|
||||
var type = cType;
|
||||
var column = Columns.Where(r => r.ColumnType == type);
|
||||
columnName.AddRange(column.Select(r => alias + "." + r.ColumnName));
|
||||
}
|
||||
|
||||
return columnName.Any();
|
||||
}
|
||||
|
||||
internal string[] GetColumnNames(string alias)
|
||||
{
|
||||
return Columns
|
||||
.Select(r => alias + "." + r.ColumnName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
internal string[] GetContentProperties()
|
||||
{
|
||||
var result = OrderedProperties
|
||||
.Where(r => r.GetCustomAttribute<ColumnAttribute>().ColumnType == ColumnTypeEnum.Content)
|
||||
.Select(r => ToLowerCamelCase(r.Name))
|
||||
.ToList();
|
||||
|
||||
if (this is WrapperWithDoc)
|
||||
{
|
||||
result.Add("document.attachment.content");
|
||||
}
|
||||
|
||||
foreach (var join in GetJoins())
|
||||
{
|
||||
var joinType = join.Value.Name;
|
||||
var joinAttr = join.Value.GetCustomAttribute<JoinAttribute>().JoinType;
|
||||
result.AddRange(join.Key.GetContentProperties()
|
||||
.Select(r => (joinAttr == JoinTypeEnum.Sub ? joinAttr + ":" : "") + ToLowerCamelCase(joinType) + "." + r));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
internal Dictionary<Wrapper, PropertyInfo> GetJoins()
|
||||
{
|
||||
var result = new Dictionary<Wrapper, PropertyInfo>();
|
||||
|
||||
var joins = GetType()
|
||||
.GetProperties()
|
||||
.Where(r => r.GetCustomAttribute<JoinAttribute>() != null)
|
||||
.ToList();
|
||||
|
||||
foreach (var join in joins)
|
||||
{
|
||||
Wrapper joinWrapper;
|
||||
if (join.PropertyType.IsGenericType)
|
||||
{
|
||||
joinWrapper = Activator.CreateInstance(join.PropertyType.GenericTypeArguments[0]) as Wrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
joinWrapper = Activator.CreateInstance(join.PropertyType) as Wrapper;
|
||||
}
|
||||
|
||||
if (joinWrapper == null) continue;
|
||||
|
||||
result.Add(joinWrapper, join);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Dictionary<string, object> GetConditions(string alias)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
|
||||
var conditions = Columns.OfType<ColumnConditionAttribute>();
|
||||
|
||||
foreach (var con in conditions.Where(r=> r.Value != null))
|
||||
{
|
||||
result.Add(alias + "." + con.ColumnName, con.Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal string ToLowerCamelCase(string value)
|
||||
{
|
||||
return char.ToLowerInvariant(value[0]) + value.Substring(1);
|
||||
}
|
||||
|
||||
internal Func<PropertiesDescriptor<T>, IPromise<IProperties>> GetProperties<T>() where T : Wrapper
|
||||
{
|
||||
var analyzers = GetAnalyzers();
|
||||
|
||||
return p =>
|
||||
{
|
||||
foreach (var c in analyzers)
|
||||
{
|
||||
var c1 = c;
|
||||
string analyzer;
|
||||
|
||||
if (c.Value.CharFilter != CharFilter.io)
|
||||
{
|
||||
analyzer = c.Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
analyzer = c1.Value.Analyzer + "custom";
|
||||
}
|
||||
|
||||
p.Text(s => s.Name(c1.Key).Analyzer(analyzer));
|
||||
}
|
||||
if (this is WrapperWithDoc)
|
||||
{
|
||||
p.Object<Document>(
|
||||
r => r.Name("document").Properties(
|
||||
q => q.Object<Attachment>(
|
||||
a => a.Name("attachment").Properties(
|
||||
w => w.Text(
|
||||
t => t.Name("content").Analyzer("document"))))));
|
||||
}
|
||||
return p;
|
||||
};
|
||||
}
|
||||
|
||||
internal Dictionary<string, ColumnAttribute> GetAnalyzers()
|
||||
{
|
||||
var result = new Dictionary<string, ColumnAttribute>();
|
||||
|
||||
foreach (var prop in OrderedProperties)
|
||||
{
|
||||
var column = prop.GetCustomAttribute<ColumnAttribute>();
|
||||
|
||||
if (column == null || column.ColumnType != ColumnTypeEnum.Content || column.Analyzer == Analyzer.standard) continue;
|
||||
|
||||
result.Add(prop.Name.ToLowerInvariant()[0] + prop.Name.Substring(1), column);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Dictionary<Type, string> GetNested()
|
||||
{
|
||||
var result = new Dictionary<Type, string>();
|
||||
|
||||
var joins = GetType().GetProperties().Where(r =>
|
||||
{
|
||||
var attr = r.GetCustomAttribute<JoinAttribute>();
|
||||
return attr != null;
|
||||
});
|
||||
|
||||
foreach (var prop in joins)
|
||||
{
|
||||
result.Add(prop.PropertyType, prop.Name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
|
||||
using Nest;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ASC.ElasticSearch.Core
|
||||
{
|
||||
public abstract class WrapperWithDoc : Wrapper
|
||||
{
|
||||
public Document Document { get; set; }
|
||||
|
||||
public const long MaxContentLength = 2 * 1024 * 1024 * 1024L;
|
||||
|
||||
protected abstract Stream GetDocumentStream();
|
||||
|
||||
[Ignore, JsonIgnore]
|
||||
public abstract string SettingsTitle { get; }
|
||||
|
||||
internal void InitDocument(bool index, ILog log)
|
||||
{
|
||||
Document = new Document
|
||||
{
|
||||
Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(""))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (!index) return;
|
||||
|
||||
using (var stream = GetDocumentStream())
|
||||
{
|
||||
if (stream == null) return;
|
||||
|
||||
Document = new Document
|
||||
{
|
||||
Data = Convert.ToBase64String(stream.GetCorrectBuffer())
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
log.Error("InitDocument FileNotFoundException", e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("InitDocument", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -30,9 +30,8 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
@ -40,13 +39,12 @@ using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Common.EF.Context;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
using ASC.ElasticSearch.Core;
|
||||
using ASC.ElasticSearch.Service;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using Elasticsearch.Net;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -57,71 +55,76 @@ namespace ASC.ElasticSearch
|
||||
public class BaseIndexerHelper
|
||||
{
|
||||
public ConcurrentDictionary<string, bool> IsExist { get; set; }
|
||||
private readonly ICacheNotify<SearchItem> Notify;
|
||||
private readonly ICacheNotify<ClearIndexAction> Notify;
|
||||
|
||||
public BaseIndexerHelper(ICacheNotify<SearchItem> cacheNotify)
|
||||
public BaseIndexerHelper(ICacheNotify<ClearIndexAction> cacheNotify)
|
||||
{
|
||||
IsExist = new ConcurrentDictionary<string, bool>();
|
||||
Notify = cacheNotify;
|
||||
Notify.Subscribe((a) =>
|
||||
{
|
||||
{
|
||||
IsExist.AddOrUpdate(a.Id, false, (q, w) => false);
|
||||
}, CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
public void Clear<T>(T t) where T : Wrapper
|
||||
public void Clear<T>(T t) where T : class, ISearchItem
|
||||
{
|
||||
Notify.Publish(new SearchItem() { Id = t.IndexName }, CacheNotifyAction.Any);
|
||||
Notify.Publish(new ClearIndexAction() { Id = t.IndexName }, CacheNotifyAction.Any);
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseIndexer<T> : IIndexer where T : Wrapper
|
||||
public class BaseIndexer<T> where T : class, ISearchItem
|
||||
{
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
protected internal T Wrapper { get { return ServiceProvider.GetService<T>(); } }
|
||||
|
||||
public string IndexName { get { return Wrapper.IndexName; } }
|
||||
|
||||
private const int QueryLimit = 1000;
|
||||
|
||||
public bool IsExist { get; set; }
|
||||
public Client Client { get; }
|
||||
public ILog Log { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public SearchSettingsHelper SearchSettingsHelper { get; }
|
||||
public BaseIndexerHelper BaseIndexerHelper { get; }
|
||||
public BaseIndexerHelper BaseIndexerHelper { get; }
|
||||
public Settings Settings { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public WebstudioDbContext WebstudioDbContext { get; }
|
||||
|
||||
public WebstudioDbContext WebstudioDbContext { get; }
|
||||
|
||||
public BaseIndexer(
|
||||
Client client,
|
||||
IOptionsMonitor<ILog> log,
|
||||
DbContextManager<WebstudioDbContext> dbContextManager,
|
||||
TenantManager tenantManager,
|
||||
SearchSettingsHelper searchSettingsHelper,
|
||||
BaseIndexerHelper baseIndexerHelper,
|
||||
BaseIndexerHelper baseIndexerHelper,
|
||||
Settings settings,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
Client = client;
|
||||
Log = log.CurrentValue;
|
||||
TenantManager = tenantManager;
|
||||
SearchSettingsHelper = searchSettingsHelper;
|
||||
BaseIndexerHelper = baseIndexerHelper;
|
||||
BaseIndexerHelper = baseIndexerHelper;
|
||||
Settings = settings;
|
||||
ServiceProvider = serviceProvider;
|
||||
WebstudioDbContext = dbContextManager.Value;
|
||||
}
|
||||
|
||||
internal void Index(T data, bool immediately = true)
|
||||
{
|
||||
BeforeIndex(data);
|
||||
|
||||
{
|
||||
CreateIfNotExist(data);
|
||||
Client.Instance.Index(data, idx => GetMeta(idx, data, immediately));
|
||||
}
|
||||
|
||||
internal void Index(List<T> data, bool immediately = true)
|
||||
{
|
||||
if (!data.Any()) return;
|
||||
|
||||
CreateIfNotExist(data[0]);
|
||||
|
||||
if (typeof(T).IsSubclassOf(typeof(WrapperWithDoc)))
|
||||
if (data[0] is ISearchItemDocument)
|
||||
{
|
||||
var currentLength = 0L;
|
||||
var portion = new List<T>();
|
||||
@ -132,17 +135,14 @@ namespace ASC.ElasticSearch
|
||||
var t = data[i];
|
||||
var runBulk = i == data.Count - 1;
|
||||
|
||||
BeforeIndex(t);
|
||||
|
||||
|
||||
if (!(t is WrapperWithDoc wwd) || wwd.Document == null || string.IsNullOrEmpty(wwd.Document.Data))
|
||||
if (!(t is ISearchItemDocument wwd) || wwd.Document == null || string.IsNullOrEmpty(wwd.Document.Data))
|
||||
{
|
||||
portion.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dLength = wwd.Document.Data.Length;
|
||||
if (dLength >= Settings.Default.MemoryLimit)
|
||||
if (dLength >= Settings.MemoryLimit)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -159,7 +159,7 @@ namespace ASC.ElasticSearch
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentLength + dLength < Settings.Default.MemoryLimit)
|
||||
if (currentLength + dLength < Settings.MemoryLimit)
|
||||
{
|
||||
portion.Add(t);
|
||||
currentLength += dLength;
|
||||
@ -177,7 +177,7 @@ namespace ASC.ElasticSearch
|
||||
Client.Instance.Bulk(r => r.IndexMany(portion1, GetMeta));
|
||||
for (var j = portionStart; j < i; j++)
|
||||
{
|
||||
if (data[j] is WrapperWithDoc doc && doc.Document != null)
|
||||
if (data[j] is ISearchItemDocument doc && doc.Document != null)
|
||||
{
|
||||
doc.Document.Data = null;
|
||||
doc.Document = null;
|
||||
@ -193,23 +193,18 @@ namespace ASC.ElasticSearch
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in data)
|
||||
{
|
||||
BeforeIndex(item);
|
||||
}
|
||||
|
||||
Client.Instance.Bulk(r => r.IndexMany(data, GetMeta));
|
||||
}
|
||||
}
|
||||
|
||||
internal void Update(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
|
||||
{
|
||||
{
|
||||
CreateIfNotExist(data);
|
||||
Client.Instance.Update(DocumentPath<T>.Id(data), r => GetMetaForUpdate(r, data, immediately, fields));
|
||||
}
|
||||
|
||||
internal void Update(T data, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
|
||||
{
|
||||
{
|
||||
CreateIfNotExist(data);
|
||||
Client.Instance.Update(DocumentPath<T>.Id(data), r => GetMetaForUpdate(r, data, action, fields, immediately));
|
||||
}
|
||||
@ -221,7 +216,7 @@ namespace ASC.ElasticSearch
|
||||
}
|
||||
|
||||
internal void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
|
||||
{
|
||||
{
|
||||
CreateIfNotExist(data);
|
||||
Client.Instance.UpdateByQuery(GetDescriptorForUpdate(data, expression, tenantId, action, fields, immediately));
|
||||
}
|
||||
@ -238,26 +233,26 @@ namespace ASC.ElasticSearch
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
Client.Instance.Flush(new FlushRequest(IndexName));
|
||||
Client.Instance.Indices.Flush(new FlushRequest(IndexName));
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Client.Instance.Refresh(new RefreshRequest(IndexName));
|
||||
Client.Instance.Indices.Refresh(new RefreshRequest(IndexName));
|
||||
}
|
||||
|
||||
internal bool CheckExist(T data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var isExist = BaseIndexerHelper.IsExist.GetOrAdd(data.IndexName, (k) => Client.Instance.IndexExists(k).Exists);
|
||||
var isExist = BaseIndexerHelper.IsExist.GetOrAdd(data.IndexName, (k) => Client.Instance.Indices.Exists(k).Exists);
|
||||
if (isExist) return true;
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
if (isExist) return true;
|
||||
|
||||
isExist = Client.Instance.IndexExists(data.IndexName).Exists;
|
||||
isExist = Client.Instance.Indices.Exists(data.IndexName).Exists;
|
||||
|
||||
_ = BaseIndexerHelper.IsExist.TryUpdate(data.IndexName, IsExist, false);
|
||||
|
||||
@ -271,68 +266,7 @@ namespace ASC.ElasticSearch
|
||||
return false;
|
||||
}
|
||||
|
||||
void IIndexer.Check()
|
||||
{
|
||||
var data = ServiceProvider.GetService<T>();
|
||||
if (!CheckExist(data)) return;
|
||||
|
||||
var result = false;
|
||||
var currentMappings = Client.Instance.GetMapping<T>(r => r.Index(data.IndexName));
|
||||
var newMappings = GetMappings(data).Invoke(new CreateIndexDescriptor(data.IndexName));
|
||||
|
||||
var newMappingDict = new Dictionary<string, string>();
|
||||
var props = newMappings.Mappings.SelectMany(r => r.Value.Properties).ToList();
|
||||
foreach (var prop in props.Where(r => r.Key.Property != null && r.Key.Property.Name != "Document"))
|
||||
{
|
||||
var propKey = prop.Key.Property.Name.ToLowerCamelCase();
|
||||
var key = newMappings.Index.Name + "." + propKey;
|
||||
if (prop.Key.Property.CustomAttributes.Any())
|
||||
{
|
||||
newMappingDict.Add(key, props.Any(r => r.Key == propKey && r.Value is INestedProperty) ? FieldType.Nested.GetStringValue() : prop.Value.Type);
|
||||
}
|
||||
|
||||
|
||||
if (prop.Value is ObjectProperty obj)
|
||||
{
|
||||
foreach (var objProp in obj.Properties)
|
||||
{
|
||||
newMappingDict.Add(key + "." + objProp.Key.Property.Name.ToLowerCamelCase(), objProp.Value.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var ind in currentMappings.Indices)
|
||||
{
|
||||
foreach (var prop in ind.Value.Mappings.SelectMany(r => r.Value.Properties).Where(r => r.Key.Name != "document"))
|
||||
{
|
||||
var key = ind.Key.Name + "." + prop.Key.Name.ToLowerCamelCase();
|
||||
|
||||
if (!newMappingDict.Contains(new KeyValuePair<string, string>(key, prop.Value.Type)))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
var nested = prop.Value as NestedProperty ?? prop.Value as ObjectProperty;
|
||||
|
||||
if (nested != null)
|
||||
{
|
||||
if (nested.Properties.Any(nProp => !newMappingDict.Contains(new KeyValuePair<string, string>(key + "." + nProp.Key.Name.ToLowerCamelCase(), nProp.Value.Type))))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (result)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
async Task IIndexer.ReIndex()
|
||||
public async Task ReIndex()
|
||||
{
|
||||
Clear();
|
||||
//((IIndexer) this).IndexAll();
|
||||
@ -350,9 +284,9 @@ namespace ASC.ElasticSearch
|
||||
WebstudioDbContext.SaveChanges();
|
||||
|
||||
Log.DebugFormat("Delete {0}", Wrapper.IndexName);
|
||||
Client.Instance.DeleteIndex(Wrapper.IndexName);
|
||||
BaseIndexerHelper.Clear(Wrapper);
|
||||
CreateIfNotExist(ServiceProvider.GetService<T>());
|
||||
Client.Instance.Indices.Delete(Wrapper.IndexName);
|
||||
BaseIndexerHelper.Clear(Wrapper);
|
||||
CreateIfNotExist(Wrapper);
|
||||
}
|
||||
|
||||
internal IReadOnlyCollection<T> Select(Expression<Func<Selector<T>, Selector<T>>> expression, bool onlyId = false)
|
||||
@ -371,132 +305,57 @@ namespace ASC.ElasticSearch
|
||||
var result = Client.Instance.Search(descriptor.GetDescriptor(this, onlyId));
|
||||
total = result.Total;
|
||||
return result.Documents;
|
||||
}
|
||||
|
||||
private void BeforeIndex(T data)
|
||||
{
|
||||
CreateIfNotExist(data);
|
||||
|
||||
if (data is WrapperWithDoc wrapperWithDoc)
|
||||
{
|
||||
wrapperWithDoc.InitDocument(SearchSettingsHelper.CanSearchByContent<T>(data.TenantId), Log);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateIfNotExist(T data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CheckExist(data)) return;
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
var columns = data.GetAnalyzers();
|
||||
var nestedColumns = data.GetNested();
|
||||
|
||||
if (!columns.Any() && !nestedColumns.Any())
|
||||
{
|
||||
Client.Instance.CreateIndex(data.IndexName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Client.Instance.CreateIndex(data.IndexName, GetMappings(data));
|
||||
}
|
||||
|
||||
IsExist = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("CreateIfNotExist", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Func<CreateIndexDescriptor, ICreateIndexRequest> GetMappings(T data)
|
||||
{
|
||||
var columns = data.GetAnalyzers();
|
||||
var nestedColumns = data.GetNested();
|
||||
|
||||
Func<AnalyzersDescriptor, IPromise<IAnalyzers>> analyzers = b =>
|
||||
{
|
||||
foreach (var c in Enum.GetNames(typeof(Analyzer)))
|
||||
{
|
||||
var c1 = c;
|
||||
b.Custom(c1 + "custom", ca => ca.Tokenizer(c1).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
|
||||
}
|
||||
|
||||
foreach (var c in columns)
|
||||
{
|
||||
if (c.Value.CharFilter == CharFilter.io) continue;
|
||||
var charFilters = new List<string>();
|
||||
foreach (var r in Enum.GetValues(typeof(CharFilter)))
|
||||
{
|
||||
if ((c.Value.CharFilter & (CharFilter)r) == (CharFilter)r) charFilters.Add(r.ToString());
|
||||
}
|
||||
|
||||
var c1 = c;
|
||||
b.Custom(c1.Key, ca => ca.Tokenizer(c1.Value.Analyzer.ToString()).Filters(c1.Value.Filter.ToString()).CharFilters(charFilters));
|
||||
}
|
||||
|
||||
if (data is WrapperWithDoc)
|
||||
{
|
||||
b.Custom("document", ca => ca.Tokenizer(Analyzer.whitespace.ToString()).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
|
||||
}
|
||||
|
||||
return b;
|
||||
};
|
||||
|
||||
Func<PropertiesDescriptor<T>, IPromise<IProperties>> nestedSelector = p =>
|
||||
{
|
||||
foreach (var c in nestedColumns)
|
||||
{
|
||||
var isNested = c.Key.IsGenericType;
|
||||
Type prop;
|
||||
MethodInfo nested;
|
||||
Type typeDescriptor;
|
||||
|
||||
if (isNested)
|
||||
{
|
||||
prop = c.Key.GenericTypeArguments[0];
|
||||
nested = p.GetType().GetMethod("Nested");
|
||||
typeDescriptor = typeof(NestedPropertyDescriptor<,>);
|
||||
}
|
||||
else
|
||||
{
|
||||
prop = c.Key;
|
||||
nested = p.GetType().GetMethod("Object");
|
||||
typeDescriptor = typeof(ObjectTypeDescriptor<,>);
|
||||
}
|
||||
|
||||
var desc = typeDescriptor.MakeGenericType(typeof(T), prop);
|
||||
|
||||
var methods = desc.GetMethods();
|
||||
var name = methods.FirstOrDefault(r => r.Name == "Name" && r.GetParameters().FirstOrDefault(q => q.ParameterType == typeof(PropertyName)) != null);
|
||||
var autoMap = methods.FirstOrDefault(r => r.Name == "AutoMap" && r.GetParameters().Length == 2);
|
||||
var props = methods.FirstOrDefault(r => r.Name == "Properties");
|
||||
if (name == null || autoMap == null || props == null) continue;
|
||||
|
||||
var param = Expression.Parameter(desc, "a");
|
||||
var nameFunc = Expression.Call(param, name, Expression.Constant(new PropertyName(c.Value.ToLowerCamelCase()))); //a.Name(value(Nest.PropertyName))
|
||||
var autoMapFunc = Expression.Call(param, autoMap, Expression.Constant(null, typeof(IPropertyVisitor)), Expression.Constant(0)); //a.AutoMap()
|
||||
|
||||
var inst = (Wrapper)Activator.CreateInstance(prop);
|
||||
var instMethods = prop.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var getProperties = instMethods.First(r => r.Name == "GetProperties").MakeGenericMethod(prop);
|
||||
var propsFunc = Expression.Call(param, props, Expression.Constant(getProperties.Invoke(inst, null))); //a.AutoMap()
|
||||
|
||||
var nestedFunc = Expression.Lambda(Expression.Block(nameFunc, autoMapFunc, propsFunc), param).Compile();
|
||||
var fooRef = nested.MakeGenericMethod(prop);
|
||||
fooRef.Invoke(p, new object[] { nestedFunc });//p.Nested<Wrapper>(r=> r.Name(c.Value.ToLowerCamelCase()).AutoMap().Properties(getProperties()))
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
return c =>
|
||||
c.Settings(r => r.Analysis(a => a.Analyzers(analyzers).CharFilters(d => d.HtmlStrip(CharFilter.html.ToString()).Mapping(CharFilter.io.ToString(), m => m.Mappings("ё => е", "Ё => Е")))))
|
||||
.Mappings(r => r.Map<T>(m => m.AutoMap<T>().Properties(data.GetProperties<T>()).Properties(nestedSelector)));
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateIfNotExist(T data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CheckExist(data)) return;
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
IPromise<IAnalyzers> analyzers(AnalyzersDescriptor b)
|
||||
{
|
||||
foreach (var c in Enum.GetNames(typeof(Analyzer)))
|
||||
{
|
||||
var c1 = c;
|
||||
b.Custom(c1 + "custom", ca => ca.Tokenizer(c1).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
|
||||
}
|
||||
|
||||
foreach (var c in Enum.GetNames(typeof(CharFilter)))
|
||||
{
|
||||
if (c == CharFilter.io.ToString()) continue;
|
||||
|
||||
var charFilters = new List<string>() { CharFilter.io.ToString(), c };
|
||||
var c1 = c;
|
||||
b.Custom(c1 + "custom", ca => ca.Tokenizer(Analyzer.whitespace.ToString()).Filters(Filter.lowercase.ToString()).CharFilters(charFilters));
|
||||
}
|
||||
|
||||
if (data is ISearchItemDocument)
|
||||
{
|
||||
b.Custom("document", ca => ca.Tokenizer(Analyzer.whitespace.ToString()).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
var createIndexResponse = Client.Instance.Indices.Create(data.IndexName,
|
||||
c =>
|
||||
c.Map<T>(m => m.AutoMap())
|
||||
.Settings(r => r.Analysis(a =>
|
||||
a.Analyzers(analyzers)
|
||||
.CharFilters(d => d.HtmlStrip(CharFilter.html.ToString())
|
||||
.Mapping(CharFilter.io.ToString(), m => m.Mappings("ё => е", "Ё => Е"))))));
|
||||
|
||||
IsExist = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("CreateIfNotExist", e);
|
||||
}
|
||||
}
|
||||
|
||||
private IIndexRequest<T> GetMeta(IndexDescriptor<T> request, T data, bool immediately = true)
|
||||
{
|
||||
@ -507,7 +366,7 @@ namespace ASC.ElasticSearch
|
||||
result.Refresh(Elasticsearch.Net.Refresh.True);
|
||||
}
|
||||
|
||||
if (data is WrapperWithDoc)
|
||||
if (data is ISearchItemDocument)
|
||||
{
|
||||
result.Pipeline("attachments");
|
||||
}
|
||||
@ -518,7 +377,7 @@ namespace ASC.ElasticSearch
|
||||
{
|
||||
var result = desc.Index(IndexName).Id(data.Id);
|
||||
|
||||
if (data is WrapperWithDoc)
|
||||
if (data is ISearchItemDocument)
|
||||
{
|
||||
result.Pipeline("attachments");
|
||||
}
|
||||
@ -707,7 +566,50 @@ namespace ASC.ElasticSearch
|
||||
var selector = ServiceProvider.GetService<Selector<T>>();
|
||||
var descriptor = func(selector).Where(r => r.TenantId, tenantId);
|
||||
return descriptor.GetDescriptorForUpdate(this, GetScriptForUpdate(data, action, fields), immediately);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<List<T>> IndexAll(Func<DateTime, (int, int, int)> getCount, Func<long, long, DateTime, List<T>> getData)
|
||||
{
|
||||
var lastIndexed = WebstudioDbContext.WebstudioIndex
|
||||
.Where(r => r.IndexName == Wrapper.IndexName)
|
||||
.Select(r => r.LastModified)
|
||||
.FirstOrDefault();
|
||||
|
||||
var (count, max, min) = getCount(lastIndexed);
|
||||
Log.Debug($"Index: {IndexName}, Count {count}, Max: {max}, Min: {min}");
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
var step = (max - min + 1) / count;
|
||||
|
||||
if (step == 0)
|
||||
{
|
||||
step = 1;
|
||||
}
|
||||
|
||||
if (step < QueryLimit)
|
||||
{
|
||||
step = QueryLimit;
|
||||
}
|
||||
|
||||
for (var i = min; i <= max; i += step)
|
||||
{
|
||||
yield return getData(i, step, lastIndexed);
|
||||
//FactoryIndexer<T>.Index(data.Cast<T>().ToList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WebstudioDbContext.AddOrUpdate(r => r.WebstudioIndex, new DbWebstudioIndex()
|
||||
{
|
||||
IndexName = Wrapper.IndexName,
|
||||
LastModified = DateTime.UtcNow
|
||||
});
|
||||
|
||||
WebstudioDbContext.SaveChanges();
|
||||
|
||||
Log.Debug($"index completed {Wrapper.IndexName}");
|
||||
}
|
||||
}
|
||||
|
||||
static class CamelCaseExtension
|
||||
@ -734,7 +636,7 @@ namespace ASC.ElasticSearch
|
||||
return services.AddKafkaService();
|
||||
}
|
||||
|
||||
public static DIHelper AddBaseIndexerService<T>(this DIHelper services) where T : Wrapper
|
||||
public static DIHelper AddBaseIndexerService<T>(this DIHelper services) where T : class, ISearchItem
|
||||
{
|
||||
services.TryAddScoped<BaseIndexer<T>>();
|
||||
|
||||
|
@ -49,12 +49,14 @@ namespace ASC.ElasticSearch
|
||||
|
||||
public ILog Log { get; }
|
||||
|
||||
public CoreConfiguration CoreConfiguration { get; }
|
||||
|
||||
public Client(IOptionsMonitor<ILog> option, CoreConfiguration coreConfiguration)
|
||||
public CoreConfiguration CoreConfiguration { get; }
|
||||
public Settings Settings { get; }
|
||||
|
||||
public Client(IOptionsMonitor<ILog> option, CoreConfiguration coreConfiguration, Settings settings)
|
||||
{
|
||||
Log = option.Get("ASC.Indexer");
|
||||
CoreConfiguration = coreConfiguration;
|
||||
CoreConfiguration = coreConfiguration;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public ElasticClient Instance
|
||||
@ -67,8 +69,7 @@ namespace ASC.ElasticSearch
|
||||
{
|
||||
if (client != null) return client;
|
||||
|
||||
var launchSettings = CoreConfiguration.GetSection<Settings>(Tenant.DEFAULT_TENANT) ??
|
||||
Settings.Default;
|
||||
var launchSettings = CoreConfiguration.GetSection<Settings>(Tenant.DEFAULT_TENANT) ?? Settings;
|
||||
|
||||
var uri = new Uri(string.Format("{0}://{1}:{2}", launchSettings.Scheme, launchSettings.Host, launchSettings.Port));
|
||||
var settings = new ConnectionSettings(new SingleNodeConnectionPool(uri))
|
||||
@ -107,7 +108,7 @@ namespace ASC.ElasticSearch
|
||||
|
||||
if (result.IsValid)
|
||||
{
|
||||
client.PutPipeline("attachments", p => p
|
||||
client.Ingest.PutPipeline("attachments", p => p
|
||||
.Processors(pp => pp
|
||||
.Attachment<Attachment>(a => a.Field("document.data").TargetField("document.attachment"))
|
||||
));
|
||||
@ -132,7 +133,8 @@ namespace ASC.ElasticSearch
|
||||
public static DIHelper AddClientService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<Client>();
|
||||
return services
|
||||
return services
|
||||
.AddSettingsService()
|
||||
.AddCoreConfigurationService();
|
||||
}
|
||||
}
|
||||
|
@ -52,89 +52,68 @@ using Nest;
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
public class FactoryIndexerHelper
|
||||
{
|
||||
public ICache Cache { get; }
|
||||
public ILog Logger { get; }
|
||||
public FactoryIndexer FactoryIndexer { get; }
|
||||
{
|
||||
public DateTime LastIndexed { get; set; }
|
||||
public string Indexing { get; set; }
|
||||
|
||||
public FactoryIndexerHelper(IOptionsMonitor<ILog> options, FactoryIndexer factoryIndexer)
|
||||
{
|
||||
Cache = AscCache.Memory;
|
||||
Logger = options.Get("ASC.Indexer");
|
||||
FactoryIndexer = factoryIndexer;
|
||||
public FactoryIndexerHelper(ICacheNotify<IndexAction> cacheNotify)
|
||||
{
|
||||
cacheNotify.Subscribe((a) =>
|
||||
{
|
||||
if (a.LastIndexed != 0)
|
||||
{
|
||||
LastIndexed = new DateTime(a.LastIndexed);
|
||||
}
|
||||
Indexing = a.Indexing;
|
||||
}, CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
public bool Support<T>(T t) where T : Wrapper
|
||||
{
|
||||
if (!FactoryIndexer.CheckState()) return false;
|
||||
|
||||
var cacheTime = DateTime.UtcNow.AddMinutes(15);
|
||||
var key = "elasticsearch " + t.IndexName;
|
||||
try
|
||||
{
|
||||
var cacheValue = Cache.Get<string>(key);
|
||||
if (!string.IsNullOrEmpty(cacheValue))
|
||||
{
|
||||
return Convert.ToBoolean(cacheValue);
|
||||
}
|
||||
|
||||
//TODO:
|
||||
//var service = new Service.Service();
|
||||
|
||||
//var result = service.Support(t.IndexName);
|
||||
|
||||
//Cache.Insert(key, result.ToString(CultureInfo.InvariantCulture).ToLower(), cacheTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cache.Insert(key, "false", cacheTime);
|
||||
Logger.Error("FactoryIndexer CheckState", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface IFactoryIndexer
|
||||
{
|
||||
void IndexAll();
|
||||
string IndexName { get; }
|
||||
void ReIndex();
|
||||
string SettingsTitle { get; }
|
||||
}
|
||||
|
||||
public class FactoryIndexer<T> where T : Wrapper
|
||||
public class FactoryIndexer<T> : IFactoryIndexer where T : class, ISearchItem
|
||||
{
|
||||
private static readonly TaskScheduler Scheduler = new LimitedConcurrencyLevelTaskScheduler(10);
|
||||
|
||||
public ILog Logger { get; }
|
||||
|
||||
public FactoryIndexerHelper FactoryIndexerHelper { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public SearchSettingsHelper SearchSettingsHelper { get; }
|
||||
public FactoryIndexer FactoryIndexerCommon { get; }
|
||||
public BaseIndexer<T> Indexer { get; }
|
||||
public Client Client { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public string IndexName { get => Indexer.IndexName; }
|
||||
|
||||
public ICache Cache { get; }
|
||||
public virtual string SettingsTitle { get => ""; }
|
||||
|
||||
public FactoryIndexer(
|
||||
IOptionsMonitor<ILog> options,
|
||||
FactoryIndexerHelper factoryIndexerSupport,
|
||||
TenantManager tenantManager,
|
||||
SearchSettingsHelper searchSettingsHelper,
|
||||
FactoryIndexer factoryIndexer,
|
||||
BaseIndexer<T> baseIndexer,
|
||||
Client client,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
{
|
||||
Cache = AscCache.Memory;
|
||||
Logger = options.Get("ASC.Indexer");
|
||||
FactoryIndexerHelper = factoryIndexerSupport;
|
||||
TenantManager = tenantManager;
|
||||
SearchSettingsHelper = searchSettingsHelper;
|
||||
FactoryIndexerCommon = factoryIndexer;
|
||||
Indexer = baseIndexer;
|
||||
Client = client;
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public bool TrySelect(Expression<Func<Selector<T>, Selector<T>>> expression, out IReadOnlyCollection<T> result)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t) || !Indexer.CheckExist(t))
|
||||
if (!Support(t) || !Indexer.CheckExist(t))
|
||||
{
|
||||
result = new List<T>();
|
||||
return false;
|
||||
@ -156,7 +135,7 @@ namespace ASC.ElasticSearch
|
||||
public bool TrySelectIds(Expression<Func<Selector<T>, Selector<T>>> expression, out List<int> result)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t) || !Indexer.CheckExist(t))
|
||||
if (!Support(t) || !Indexer.CheckExist(t))
|
||||
{
|
||||
result = new List<int>();
|
||||
return false;
|
||||
@ -179,7 +158,7 @@ namespace ASC.ElasticSearch
|
||||
public bool TrySelectIds(Expression<Func<Selector<T>, Selector<T>>> expression, out List<int> result, out long total)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t) || !Indexer.CheckExist(t))
|
||||
if (!Support(t) || !Indexer.CheckExist(t))
|
||||
{
|
||||
result = new List<int>();
|
||||
total = 0;
|
||||
@ -209,7 +188,7 @@ namespace ASC.ElasticSearch
|
||||
public bool Index(T data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return false;
|
||||
if (!Support(t)) return false;
|
||||
|
||||
try
|
||||
{
|
||||
@ -226,7 +205,7 @@ namespace ASC.ElasticSearch
|
||||
public void Index(List<T> data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t) || !data.Any()) return;
|
||||
if (!Support(t) || !data.Any()) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -258,7 +237,7 @@ namespace ASC.ElasticSearch
|
||||
public void Update(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -273,7 +252,7 @@ namespace ASC.ElasticSearch
|
||||
public void Update(T data, UpdateAction action, Expression<Func<T, IList>> field, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -288,7 +267,7 @@ namespace ASC.ElasticSearch
|
||||
public void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true, params Expression<Func<T, object>>[] fields)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -304,7 +283,7 @@ namespace ASC.ElasticSearch
|
||||
public void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -320,7 +299,7 @@ namespace ASC.ElasticSearch
|
||||
public void Delete(T data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
try
|
||||
{
|
||||
@ -335,7 +314,7 @@ namespace ASC.ElasticSearch
|
||||
public void Delete(Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
|
||||
var tenant = TenantManager.GetCurrentTenant().TenantId;
|
||||
|
||||
@ -352,35 +331,35 @@ namespace ASC.ElasticSearch
|
||||
public Task<bool> IndexAsync(T data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return Task.FromResult(false);
|
||||
if (!Support(t)) return Task.FromResult(false);
|
||||
return Queue(() => Indexer.Index(data, immediately));
|
||||
}
|
||||
|
||||
public Task<bool> IndexAsync(List<T> data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return Task.FromResult(false);
|
||||
if (!Support(t)) return Task.FromResult(false);
|
||||
return Queue(() => Indexer.Index(data, immediately));
|
||||
}
|
||||
|
||||
public Task<bool> UpdateAsync(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return Task.FromResult(false);
|
||||
if (!Support(t)) return Task.FromResult(false);
|
||||
return Queue(() => Indexer.Update(data, immediately, fields));
|
||||
}
|
||||
|
||||
public Task<bool> DeleteAsync(T data, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return Task.FromResult(false);
|
||||
if (!Support(t)) return Task.FromResult(false);
|
||||
return Queue(() => Indexer.Delete(data, immediately));
|
||||
}
|
||||
|
||||
public Task<bool> DeleteAsync(Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true)
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return Task.FromResult(false);
|
||||
if (!Support(t)) return Task.FromResult(false);
|
||||
var tenant = TenantManager.GetCurrentTenant().TenantId;
|
||||
return Queue(() => Indexer.Delete(expression, tenant, immediately));
|
||||
}
|
||||
@ -389,14 +368,14 @@ namespace ASC.ElasticSearch
|
||||
public void Flush()
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
Indexer.Flush();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
var t = ServiceProvider.GetService<T>();
|
||||
if (!FactoryIndexerHelper.Support(t)) return;
|
||||
if (!Support(t)) return;
|
||||
Indexer.Refresh();
|
||||
}
|
||||
|
||||
@ -423,24 +402,79 @@ namespace ASC.ElasticSearch
|
||||
task.ConfigureAwait(false);
|
||||
task.Start(Scheduler);
|
||||
return task;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void IndexAll()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void ReIndex()
|
||||
{
|
||||
Indexer.ReIndex();
|
||||
}
|
||||
|
||||
public bool Support(T t)
|
||||
{
|
||||
if (!FactoryIndexerCommon.CheckState()) return false;
|
||||
|
||||
var cacheTime = DateTime.UtcNow.AddMinutes(15);
|
||||
var key = "elasticsearch " + t.IndexName;
|
||||
try
|
||||
{
|
||||
var cacheValue = Cache.Get<string>(key);
|
||||
if (!string.IsNullOrEmpty(cacheValue))
|
||||
{
|
||||
return Convert.ToBoolean(cacheValue);
|
||||
}
|
||||
|
||||
//TODO:
|
||||
//var service = new Service.Service();
|
||||
|
||||
//var result = service.Support(t.IndexName);
|
||||
|
||||
//Cache.Insert(key, result.ToString(CultureInfo.InvariantCulture).ToLower(), cacheTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cache.Insert(key, "false", cacheTime);
|
||||
Logger.Error("FactoryIndexer CheckState", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FactoryIndexer
|
||||
{
|
||||
private static ICache cache = AscCache.Memory;
|
||||
internal IContainer Builder { get; set; }
|
||||
private static ICache cache = AscCache.Memory;
|
||||
|
||||
public FactoryIndexerHelper FactoryIndexerHelper { get; }
|
||||
internal ILifetimeScope Builder { get; set; }
|
||||
internal static bool Init { get; set; }
|
||||
public ILog Log { get; }
|
||||
public Client Client { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
|
||||
public FactoryIndexer(
|
||||
IContainer container,
|
||||
ILifetimeScope container,
|
||||
FactoryIndexerHelper factoryIndexerHelper,
|
||||
Client client,
|
||||
IOptionsMonitor<ILog> options,
|
||||
CoreBaseSettings coreBaseSettings) : this(null, factoryIndexerHelper, client, options, coreBaseSettings)
|
||||
{
|
||||
Builder = container;
|
||||
}
|
||||
|
||||
public FactoryIndexer(
|
||||
IContainer container,
|
||||
FactoryIndexerHelper factoryIndexerHelper,
|
||||
Client client,
|
||||
IOptionsMonitor<ILog> options,
|
||||
CoreBaseSettings coreBaseSettings)
|
||||
{
|
||||
FactoryIndexerHelper = factoryIndexerHelper;
|
||||
Client = client;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
|
||||
@ -507,23 +541,23 @@ namespace ASC.ElasticSearch
|
||||
public object GetState(TenantUtil tenantUtil)
|
||||
{
|
||||
var indices = CoreBaseSettings.Standalone ?
|
||||
Client.Instance.CatIndices(new CatIndicesRequest { SortByColumns = new[] { "index" } }).Records.Select(r => new
|
||||
Client.Instance.Cat.Indices(new CatIndicesRequest { SortByColumns = new[] { "index" } }).Records.Select(r => new
|
||||
{
|
||||
r.Index,
|
||||
r.DocsCount,
|
||||
r.StoreSize
|
||||
}) :
|
||||
}) :
|
||||
null;
|
||||
|
||||
State state = null;
|
||||
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
//TODO
|
||||
//using (var service = new ServiceClient())
|
||||
//{
|
||||
// state = service.GetState();
|
||||
//}
|
||||
{
|
||||
state = new State
|
||||
{
|
||||
Indexing = FactoryIndexerHelper.Indexing,
|
||||
LastIndexed = FactoryIndexerHelper.LastIndexed != DateTime.MinValue ? FactoryIndexerHelper.LastIndexed : default(DateTime?)
|
||||
};
|
||||
|
||||
if (state.LastIndexed.HasValue)
|
||||
{
|
||||
@ -544,9 +578,9 @@ namespace ASC.ElasticSearch
|
||||
if (!CoreBaseSettings.Standalone) return;
|
||||
|
||||
var generic = typeof(BaseIndexer<>);
|
||||
var indexers = Builder.Resolve<IEnumerable<Wrapper>>()
|
||||
var indexers = Builder.Resolve<IEnumerable<IFactoryIndexer>>()
|
||||
.Where(r => string.IsNullOrEmpty(name) || r.IndexName == name)
|
||||
.Select(r => (IIndexer)Activator.CreateInstance(generic.MakeGenericType(r.GetType()), r));
|
||||
.Select(r => (IFactoryIndexer)Activator.CreateInstance(generic.MakeGenericType(r.GetType()), r));
|
||||
|
||||
foreach (var indexer in indexers)
|
||||
{
|
||||
@ -559,25 +593,23 @@ namespace ASC.ElasticSearch
|
||||
{
|
||||
public static DIHelper AddFactoryIndexerService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<FactoryIndexerHelper>();
|
||||
services.TryAddScoped<FactoryIndexer>();
|
||||
return services
|
||||
.AddClientService()
|
||||
.AddCoreBaseSettingsService();
|
||||
}
|
||||
|
||||
public static DIHelper AddFactoryIndexerHelperService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<FactoryIndexerHelper>();
|
||||
return services
|
||||
.AddFactoryIndexerService();
|
||||
}
|
||||
|
||||
public static DIHelper AddFactoryIndexerService<T>(this DIHelper services) where T : Wrapper
|
||||
{
|
||||
services.TryAddScoped<FactoryIndexer<T>>();
|
||||
public static DIHelper AddFactoryIndexerService<T>(this DIHelper services, bool addBase = true) where T : class, ISearchItem
|
||||
{
|
||||
if (addBase)
|
||||
{
|
||||
services.TryAddScoped<FactoryIndexer<T>>();
|
||||
}
|
||||
|
||||
services.TryAddScoped<Selector<T>>();
|
||||
|
||||
return services
|
||||
.AddFactoryIndexerHelperService()
|
||||
.AddTenantManagerService()
|
||||
.AddFactoryIndexerService()
|
||||
.AddClientService()
|
||||
|
@ -23,16 +23,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
internal interface IIndexer
|
||||
public interface IIndexer
|
||||
{
|
||||
string IndexName { get; }
|
||||
|
||||
void Check();
|
||||
void IndexAll();
|
||||
|
||||
Task ReIndex();
|
||||
}
|
||||
|
196
common/services/ASC.ElasticSearch/Service/Launcher.cs
Normal file
196
common/services/ASC.ElasticSearch/Service/Launcher.cs
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.ElasticSearch.Service;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.ElasticSearch
|
||||
{
|
||||
public class ServiceLauncher : IHostedService
|
||||
{
|
||||
private ILog Log { get; }
|
||||
private ICacheNotify<AscCacheItem> Notify { get; }
|
||||
public ICacheNotify<IndexAction> IndexNotify { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public IContainer Container { get; }
|
||||
private bool IsStarted { get; set; }
|
||||
private CancellationTokenSource CancellationTokenSource { get; set; }
|
||||
private Timer Timer { get; set; }
|
||||
private TimeSpan Period { get; set; }
|
||||
|
||||
public ServiceLauncher(
|
||||
IOptionsMonitor<ILog> options,
|
||||
ICacheNotify<AscCacheItem> notify,
|
||||
ICacheNotify<IndexAction> indexNotify,
|
||||
IServiceProvider serviceProvider,
|
||||
IContainer container,
|
||||
Settings settings)
|
||||
{
|
||||
Log = options.Get("ASC.Indexer");
|
||||
Notify = notify;
|
||||
IndexNotify = indexNotify;
|
||||
ServiceProvider = serviceProvider;
|
||||
Container = container;
|
||||
CancellationTokenSource = new CancellationTokenSource();
|
||||
Period = TimeSpan.FromMinutes(settings.Period.Value);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
Notify.Subscribe(async (item) =>
|
||||
{
|
||||
while (IsStarted)
|
||||
{
|
||||
await Task.Delay(10000);
|
||||
}
|
||||
IndexAll(true);
|
||||
}, CacheNotifyAction.Any);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Subscribe on start", e);
|
||||
}
|
||||
|
||||
var task = new Task(async () =>
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var factoryIndexer = scope.ServiceProvider.GetService<FactoryIndexer>();
|
||||
var service = scope.ServiceProvider.GetService<Service.Service>();
|
||||
|
||||
while (!factoryIndexer.CheckState(false))
|
||||
{
|
||||
if (CancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(10000);
|
||||
}
|
||||
|
||||
service.Subscribe();
|
||||
Timer = new Timer(_ => IndexAll(), null, TimeSpan.Zero, TimeSpan.Zero);
|
||||
|
||||
}, CancellationTokenSource.Token, TaskCreationOptions.LongRunning);
|
||||
|
||||
task.Start();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
IsStarted = false;
|
||||
|
||||
if (Timer != null)
|
||||
{
|
||||
Timer.Dispose();
|
||||
}
|
||||
|
||||
CancellationTokenSource.Cancel();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void IndexAll(bool reindex = false)
|
||||
{
|
||||
Timer.Change(-1, -1);
|
||||
IsStarted = true;
|
||||
|
||||
using var scope = Container.BeginLifetimeScope();
|
||||
var wrappers = scope.Resolve<IEnumerable<IFactoryIndexer>>();
|
||||
|
||||
foreach (var w in wrappers)
|
||||
{
|
||||
IndexProduct(w, reindex);
|
||||
}
|
||||
|
||||
Timer.Change(Period, Period);
|
||||
IndexNotify.Publish(new IndexAction() { Indexing = "", LastIndexed = DateTime.Now.Ticks }, CacheNotifyAction.Any);
|
||||
IsStarted = false;
|
||||
}
|
||||
|
||||
public void IndexProduct(IFactoryIndexer product, bool reindex)
|
||||
{
|
||||
if (reindex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsStarted) return;
|
||||
|
||||
Log.DebugFormat("Product reindex {0}", product.IndexName);
|
||||
product.ReIndex();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.ErrorFormat("Product reindex {0}", product.IndexName);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!IsStarted) return;
|
||||
|
||||
Log.DebugFormat("Product {0}", product.IndexName);
|
||||
IndexNotify.Publish(new IndexAction() { Indexing = product.IndexName, LastIndexed = 0 }, CacheNotifyAction.Any);
|
||||
product.IndexAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.ErrorFormat("Product {0}", product.IndexName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServiceLauncherExtension
|
||||
{
|
||||
public static DIHelper AddServiceLauncher(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<ServiceLauncher>();
|
||||
services.TryAddSingleton<Service.Service>();
|
||||
|
||||
return services
|
||||
.AddSettingsService()
|
||||
.AddFactoryIndexerService();
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.ElasticSearch.Core;
|
||||
@ -38,26 +39,36 @@ using Autofac;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ASC.ElasticSearch.Service
|
||||
{
|
||||
{
|
||||
public class Service
|
||||
{
|
||||
public FactoryIndexer FactoryIndexer { get; }
|
||||
public IContainer Container { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public ICacheNotify<ReIndexAction> CacheNotify { get; }
|
||||
|
||||
public Service(FactoryIndexer factoryIndexer, IServiceProvider serviceProvider)
|
||||
public Service(IContainer container, IServiceProvider serviceProvider, ICacheNotify<ReIndexAction> cacheNotify)
|
||||
{
|
||||
FactoryIndexer = factoryIndexer;
|
||||
Container = container;
|
||||
ServiceProvider = serviceProvider;
|
||||
CacheNotify = cacheNotify;
|
||||
}
|
||||
|
||||
public void Subscribe()
|
||||
{
|
||||
CacheNotify.Subscribe((a) =>
|
||||
{
|
||||
ReIndex(a.Names.ToList(), a.Tenant);
|
||||
}, CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
public bool Support(string table)
|
||||
{
|
||||
return FactoryIndexer.Builder.Resolve<IEnumerable<Wrapper>>().Any(r => r.IndexName == table);
|
||||
return Container.Resolve<IEnumerable<IFactoryIndexer>>().Any(r => r.IndexName == table);
|
||||
}
|
||||
|
||||
public void ReIndex(List<string> toReIndex, int tenant)
|
||||
{
|
||||
var allItems = FactoryIndexer.Builder.Resolve<IEnumerable<Wrapper>>().ToList();
|
||||
var allItems = Container.Resolve<IEnumerable<IFactoryIndexer>>().ToList();
|
||||
var tasks = new List<Task>(toReIndex.Count);
|
||||
|
||||
foreach (var item in toReIndex)
|
||||
@ -69,6 +80,8 @@ namespace ASC.ElasticSearch.Service
|
||||
var instance = (IIndexer)Activator.CreateInstance(generic.MakeGenericType(index.GetType()), index);
|
||||
tasks.Add(instance.ReIndex());
|
||||
}
|
||||
|
||||
if (!tasks.Any()) return;
|
||||
|
||||
Task.WhenAll(tasks).ContinueWith(r =>
|
||||
{
|
||||
|
@ -24,54 +24,47 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Configuration;
|
||||
using ASC.ElasticSearch.Config;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Utils;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ASC.ElasticSearch.Service
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
private static readonly Settings DefaultSettings;
|
||||
|
||||
static Settings()
|
||||
public Settings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Settings(IConfiguration configuration)
|
||||
{
|
||||
DefaultSettings = new Settings
|
||||
{
|
||||
Scheme = "http",
|
||||
Host = "localhost",
|
||||
Port = 9200,
|
||||
Period = 1,
|
||||
MemoryLimit = 10 * 1024 * 1024L
|
||||
};
|
||||
|
||||
|
||||
var cfg = ConfigurationManager.GetSection("elastic") as ElasticSection;
|
||||
if (cfg == null) return;
|
||||
|
||||
DefaultSettings = new Settings
|
||||
{
|
||||
Scheme = cfg.Scheme,
|
||||
Host = cfg.Host,
|
||||
Port = cfg.Port,
|
||||
Period = cfg.Period,
|
||||
MemoryLimit = cfg.MemoryLimit
|
||||
};
|
||||
|
||||
var cfg = configuration.GetSetting<Settings>("elastic");
|
||||
Scheme = cfg.Scheme ?? "http";
|
||||
Host = cfg.Host ?? "localhost";
|
||||
Port = cfg.Port ?? 9200;
|
||||
Period = cfg.Period ?? 1;
|
||||
MemoryLimit = cfg.MemoryLimit ?? 10 * 1024 * 1024L;
|
||||
}
|
||||
|
||||
public string Host { get; set; }
|
||||
|
||||
public int Port { get; set; }
|
||||
public int? Port { get; set; }
|
||||
|
||||
public string Scheme { get; set; }
|
||||
|
||||
public int Period { get; set; }
|
||||
public int? Period { get; set; }
|
||||
|
||||
public long MemoryLimit { get; set; }
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get { return DefaultSettings; }
|
||||
public long? MemoryLimit { get; set; }
|
||||
}
|
||||
|
||||
public static class SettingsExtention
|
||||
{
|
||||
public static DIHelper AddSettingsService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<Settings>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,16 @@
|
||||
|
||||
package ASC.ElasticSearch;
|
||||
|
||||
message SearchItem {
|
||||
message ClearIndexAction {
|
||||
string Id = 1;
|
||||
}
|
||||
|
||||
message ReIndexAction {
|
||||
int32 Tenant = 1;
|
||||
repeated string Names = 2;
|
||||
}
|
||||
|
||||
message IndexAction {
|
||||
string Indexing = 1;
|
||||
int64 LastIndexed = 2;
|
||||
}
|
@ -35,6 +35,7 @@ using ASC.Files.Resources;
|
||||
using ASC.Web.Core;
|
||||
using ASC.Web.Core.PublicResources;
|
||||
using ASC.Web.Files.Classes;
|
||||
using ASC.Web.Files.Core.Search;
|
||||
|
||||
namespace ASC.Web.Files.Configuration
|
||||
{
|
||||
@ -46,6 +47,8 @@ namespace ASC.Web.Files.Configuration
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
public AuthContext AuthContext { get; }
|
||||
public UserManager UserManager { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
//public SubscriptionManager SubscriptionManager { get; }
|
||||
|
||||
public ProductEntryPoint()
|
||||
@ -97,6 +100,7 @@ namespace ASC.Web.Files.Configuration
|
||||
UserOpportunities = userOpportunities,
|
||||
CanNotBeDisabled = true,
|
||||
};
|
||||
|
||||
//SearchHandlerManager.Registry(new SearchHandler());
|
||||
}
|
||||
|
||||
@ -177,7 +181,8 @@ namespace ASC.Web.Files.Configuration
|
||||
.AddAuthContextService()
|
||||
.AddUserManagerService()
|
||||
.AddGlobalService()
|
||||
.AddFilesSubscriptionManagerService();
|
||||
.AddFilesSubscriptionManagerService()
|
||||
.AddFactoryIndexerFileService();
|
||||
}
|
||||
}
|
||||
}
|
@ -53,8 +53,10 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
public FilesDbContext FilesDbContext { get; }
|
||||
|
||||
protected internal int TenantID { get; }
|
||||
private int tenantID;
|
||||
protected internal int TenantID { get => tenantID != 0 ? tenantID : (tenantID = TenantManager.GetCurrentTenant().TenantId); }
|
||||
public UserManager UserManager { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public TenantUtil TenantUtil { get; }
|
||||
public SetupInfo SetupInfo { get; }
|
||||
public TenantExtra TenantExtra { get; }
|
||||
@ -81,8 +83,8 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
cache = AscCache.Memory;
|
||||
FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId);
|
||||
TenantID = tenantManager.GetCurrentTenant().TenantId;
|
||||
UserManager = userManager;
|
||||
TenantManager = tenantManager;
|
||||
TenantUtil = tenantUtil;
|
||||
SetupInfo = setupInfo;
|
||||
TenantExtra = tenantExtra;
|
||||
@ -100,7 +102,7 @@ namespace ASC.Files.Core.Data
|
||||
return set.Where(r => r.TenantId == TenantID);
|
||||
}
|
||||
|
||||
protected IQueryable<DbFile> GetFileQuery(Expression<Func<DbFile, bool>> where)
|
||||
protected internal IQueryable<DbFile> GetFileQuery(Expression<Func<DbFile, bool>> where)
|
||||
{
|
||||
return Query(FilesDbContext.Files)
|
||||
.Where(where);
|
||||
|
@ -29,6 +29,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
@ -55,8 +56,10 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
internal class FileDao : AbstractDao, IFileDao<int>
|
||||
{
|
||||
public const long MaxContentLength = 2 * 1024 * 1024 * 1024L;
|
||||
|
||||
private static readonly object syncRoot = new object();
|
||||
public FactoryIndexer<FilesWrapper> FactoryIndexer { get; }
|
||||
public FactoryIndexer<DbFile> FactoryIndexer { get; }
|
||||
public GlobalStore GlobalStore { get; }
|
||||
public GlobalSpace GlobalSpace { get; }
|
||||
public GlobalFolder GlobalFolder { get; }
|
||||
@ -66,7 +69,7 @@ namespace ASC.Files.Core.Data
|
||||
public CrossDao CrossDao { get; }
|
||||
|
||||
public FileDao(
|
||||
FactoryIndexer<FilesWrapper> factoryIndexer,
|
||||
FactoryIndexer<DbFile> factoryIndexer,
|
||||
UserManager userManager,
|
||||
DbContextManager<FilesDbContext> dbContextManager,
|
||||
TenantManager tenantManager,
|
||||
@ -252,7 +255,7 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
var func = GetFuncForSearch(parentId, orderBy, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders);
|
||||
|
||||
Expression<Func<Selector<FilesWrapper>, Selector<FilesWrapper>>> expression = s => func(s);
|
||||
Expression<Func<Selector<DbFile>, Selector<DbFile>>> expression = s => func(s);
|
||||
|
||||
if (FactoryIndexer.TrySelectIds(expression, out var searchIds))
|
||||
{
|
||||
@ -368,6 +371,8 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
var isNew = false;
|
||||
List<int> parentFoldersIds;
|
||||
DbFile toInsert = null;
|
||||
|
||||
lock (syncRoot)
|
||||
{
|
||||
using var tx = FilesDbContext.Database.BeginTransaction();
|
||||
@ -400,7 +405,7 @@ namespace ASC.Files.Core.Data
|
||||
FilesDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
var toInsert = new DbFile
|
||||
toInsert = new DbFile
|
||||
{
|
||||
Id = file.ID,
|
||||
Version = file.Version,
|
||||
@ -428,14 +433,15 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
file.PureTitle = file.Title;
|
||||
|
||||
parentFoldersIds =
|
||||
var parentFolders =
|
||||
FilesDbContext.Tree
|
||||
.Where(r => r.FolderId == file.FolderID)
|
||||
.OrderByDescending(r => r.Level)
|
||||
.Select(r => r.ParentId)
|
||||
.ToList();
|
||||
|
||||
if (parentFoldersIds.Count > 0)
|
||||
parentFoldersIds = parentFolders.Select(r => r.ParentId).ToList();
|
||||
|
||||
if (parentFoldersIds.Any())
|
||||
{
|
||||
var folderToUpdate = FilesDbContext.Folders
|
||||
.Where(r => parentFoldersIds.Any(a => a == r.Id));
|
||||
@ -449,6 +455,8 @@ namespace ASC.Files.Core.Data
|
||||
FilesDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
toInsert.Folders = parentFolders;
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
RecalculateFilesCount(file.FolderID);
|
||||
@ -476,7 +484,7 @@ namespace ASC.Files.Core.Data
|
||||
}
|
||||
}
|
||||
|
||||
FactoryIndexer.IndexAsync(FilesWrapper.GetFilesWrapper(ServiceProvider, file, parentFoldersIds));
|
||||
FactoryIndexer.IndexAsync(InitDocument(toInsert));
|
||||
|
||||
return GetFile(file.ID);
|
||||
}
|
||||
@ -502,6 +510,8 @@ namespace ASC.Files.Core.Data
|
||||
}
|
||||
}
|
||||
|
||||
DbFile toUpdate = null;
|
||||
|
||||
List<int> parentFoldersIds;
|
||||
lock (syncRoot)
|
||||
{
|
||||
@ -516,7 +526,7 @@ namespace ASC.Files.Core.Data
|
||||
if (file.CreateBy == default) file.CreateBy = AuthContext.CurrentAccount.ID;
|
||||
if (file.CreateOn == default) file.CreateOn = TenantUtil.DateTimeNow();
|
||||
|
||||
var toUpdate = FilesDbContext.Files
|
||||
toUpdate = FilesDbContext.Files
|
||||
.Where(r => r.Id == file.ID && r.Version == file.Version)
|
||||
.FirstOrDefault();
|
||||
|
||||
@ -541,13 +551,14 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
file.PureTitle = file.Title;
|
||||
|
||||
parentFoldersIds = FilesDbContext.Tree
|
||||
var parentFolders = FilesDbContext.Tree
|
||||
.Where(r => r.FolderId == file.FolderID)
|
||||
.OrderByDescending(r => r.Level)
|
||||
.Select(r => r.ParentId)
|
||||
.ToList();
|
||||
|
||||
if (parentFoldersIds.Count > 0)
|
||||
parentFoldersIds = parentFolders.Select(r => r.ParentId).ToList();
|
||||
|
||||
if (parentFoldersIds.Any())
|
||||
{
|
||||
var folderToUpdate = FilesDbContext.Folders
|
||||
.Where(r => parentFoldersIds.Any(a => a == r.Id));
|
||||
@ -560,6 +571,8 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
FilesDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
toUpdate.Folders = parentFolders;
|
||||
}
|
||||
|
||||
if (fileStream != null)
|
||||
@ -579,7 +592,7 @@ namespace ASC.Files.Core.Data
|
||||
}
|
||||
}
|
||||
|
||||
FactoryIndexer.IndexAsync(FilesWrapper.GetFilesWrapper(ServiceProvider, file, parentFoldersIds));
|
||||
FactoryIndexer.IndexAsync(InitDocument(toUpdate));
|
||||
|
||||
return GetFile(file.ID);
|
||||
}
|
||||
@ -639,6 +652,11 @@ namespace ASC.Files.Core.Data
|
||||
var toDeleteFiles = Query(FilesDbContext.Files).Where(r => r.Id == fileId);
|
||||
FilesDbContext.RemoveRange(toDeleteFiles);
|
||||
|
||||
foreach (var d in toDeleteFiles)
|
||||
{
|
||||
FactoryIndexer.DeleteAsync(d);
|
||||
}
|
||||
|
||||
var toDeleteLinks = Query(FilesDbContext.TagLink).Where(r => r.EntryId == fileId.ToString()).Where(r => r.EntryType == FileEntryType.File);
|
||||
FilesDbContext.RemoveRange(toDeleteFiles);
|
||||
|
||||
@ -661,9 +679,11 @@ namespace ASC.Files.Core.Data
|
||||
if (deleteFolder)
|
||||
DeleteFolder(fileId);
|
||||
|
||||
var wrapper = ServiceProvider.GetService<FilesWrapper>();
|
||||
wrapper.Id = fileId;
|
||||
FactoryIndexer.DeleteAsync(wrapper);
|
||||
var toDeleteFile = toDeleteFiles.FirstOrDefault(r => r.CurrentVersion);
|
||||
if (toDeleteFile != null)
|
||||
{
|
||||
FactoryIndexer.DeleteAsync(toDeleteFile);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsExist(string title, object folderId)
|
||||
@ -699,6 +719,8 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
if (fileId == default) return default;
|
||||
|
||||
List<DbFile> toUpdate;
|
||||
|
||||
using (var tx = FilesDbContext.Database.BeginTransaction())
|
||||
{
|
||||
var fromFolders = Query(FilesDbContext.Files)
|
||||
@ -707,7 +729,7 @@ namespace ASC.Files.Core.Data
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var toUpdate = Query(FilesDbContext.Files)
|
||||
toUpdate = Query(FilesDbContext.Files)
|
||||
.Where(r => r.Id == fileId)
|
||||
.ToList();
|
||||
|
||||
@ -729,20 +751,19 @@ namespace ASC.Files.Core.Data
|
||||
RecalculateFilesCount(toFolderId);
|
||||
}
|
||||
|
||||
var parentFoldersIds =
|
||||
var parentFolders =
|
||||
FilesDbContext.Tree
|
||||
.Where(r => r.FolderId == toFolderId)
|
||||
.OrderByDescending(r => r.Level)
|
||||
.Select(r => r.ParentId)
|
||||
.ToList();
|
||||
|
||||
var wrapper = ServiceProvider.GetService<FilesWrapper>();
|
||||
wrapper.Id = fileId;
|
||||
wrapper.Folders = parentFoldersIds.Select(r => new FilesFoldersWrapper() { FolderId = r.ToString() }).ToList();
|
||||
var toUpdateFile = toUpdate.FirstOrDefault(r => r.CurrentVersion);
|
||||
|
||||
FactoryIndexer.Update(wrapper,
|
||||
UpdateAction.Replace,
|
||||
w => w.Folders);
|
||||
if (toUpdateFile != null)
|
||||
{
|
||||
toUpdateFile.Folders = parentFolders;
|
||||
FactoryIndexer.Update(toUpdateFile, UpdateAction.Replace, w => w.Folders);
|
||||
}
|
||||
|
||||
return fileId;
|
||||
}
|
||||
@ -812,7 +833,6 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
public int FileRename(File<int> file, string newTitle)
|
||||
{
|
||||
var fileIdString = file.ID.ToString();
|
||||
newTitle = Global.ReplaceInvalidCharsAndTruncate(newTitle);
|
||||
var toUpdate = Query(FilesDbContext.Files)
|
||||
.Where(r => r.Id == file.ID)
|
||||
@ -825,6 +845,8 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
FilesDbContext.SaveChanges();
|
||||
|
||||
FactoryIndexer.UpdateAsync(toUpdate, true, r => r.Title, r => r.ModifiedBy, r => r.ModifiedOn);
|
||||
|
||||
return file.ID;
|
||||
}
|
||||
|
||||
@ -1175,7 +1197,7 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
#endregion
|
||||
|
||||
private Func<Selector<FilesWrapper>, Selector<FilesWrapper>> GetFuncForSearch(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false)
|
||||
private Func<Selector<DbFile>, Selector<DbFile>> GetFuncForSearch(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false)
|
||||
{
|
||||
return s =>
|
||||
{
|
||||
@ -1187,11 +1209,11 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
if (withSubfolders)
|
||||
{
|
||||
result.In(a => a.Folders.Select(r => r.FolderId), new[] { parentId.ToString() });
|
||||
result.In(a => a.Folders.Select(r => r.ParentId), new[] { parentId });
|
||||
}
|
||||
else
|
||||
{
|
||||
result.InAll(a => a.Folders.Select(r => r.FolderId), new[] { parentId.ToString() });
|
||||
result.InAll(a => a.Folders.Select(r => r.ParentId), new[] { parentId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1209,7 +1231,7 @@ namespace ASC.Files.Core.Data
|
||||
// result.Sort(r => r.Title, orderBy.IsAsc);
|
||||
// break;
|
||||
case SortedByType.DateAndTime:
|
||||
result.Sort(r => r.LastModifiedOn, orderBy.IsAsc);
|
||||
result.Sort(r => r.ModifiedOn, orderBy.IsAsc);
|
||||
break;
|
||||
case SortedByType.DateAndTimeCreation:
|
||||
result.Sort(r => r.CreateOn, orderBy.IsAsc);
|
||||
@ -1314,6 +1336,36 @@ namespace ASC.Files.Core.Data
|
||||
file.Forcesave = r.file.Forcesave;
|
||||
return file;
|
||||
}
|
||||
|
||||
internal protected DbFile InitDocument(DbFile dbFile)
|
||||
{
|
||||
if (!FactoryIndexer.CanSearchByContent())
|
||||
{
|
||||
dbFile.Document = new Document
|
||||
{
|
||||
Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(""))
|
||||
};
|
||||
return dbFile;
|
||||
}
|
||||
|
||||
var file = ServiceProvider.GetService<File<int>>();
|
||||
file.ID = dbFile.Id;
|
||||
file.Title = dbFile.Title;
|
||||
file.Version = dbFile.Version;
|
||||
file.ContentLength = dbFile.ContentLength;
|
||||
|
||||
if (!IsExistOnStorage(file) || file.ContentLength > MaxContentLength) return dbFile;
|
||||
|
||||
using var stream = GetFileStream(file);
|
||||
if (stream == null) return dbFile;
|
||||
|
||||
dbFile.Document = new Document
|
||||
{
|
||||
Data = Convert.ToBase64String(stream.GetCorrectBuffer())
|
||||
};
|
||||
|
||||
return dbFile;
|
||||
}
|
||||
}
|
||||
|
||||
public class DbFileQuery
|
||||
@ -1344,7 +1396,7 @@ namespace ASC.Files.Core.Data
|
||||
.AddAuthContextService()
|
||||
.AddGlobalStoreService()
|
||||
.AddGlobalSpaceService()
|
||||
.AddFactoryIndexerService<FilesWrapper>()
|
||||
.AddFactoryIndexerFileService()
|
||||
.AddGlobalFolderService()
|
||||
.AddChunkedUploadSessionHolderService()
|
||||
.AddFolderDaoService();
|
||||
|
@ -41,7 +41,6 @@ using ASC.Files.Core.Thirdparty;
|
||||
using ASC.Files.Resources;
|
||||
using ASC.Files.Thirdparty.ProviderDao;
|
||||
using ASC.Web.Files.Classes;
|
||||
using ASC.Web.Files.Core.Search;
|
||||
using ASC.Web.Studio.Core;
|
||||
using ASC.Web.Studio.UserControls.Statistics;
|
||||
using ASC.Web.Studio.Utility;
|
||||
@ -59,14 +58,14 @@ namespace ASC.Files.Core.Data
|
||||
private const string trash = "trash";
|
||||
private const string projects = "projects";
|
||||
|
||||
public FactoryIndexer<FoldersWrapper> FactoryIndexer { get; }
|
||||
public FactoryIndexer<DbFolder> FactoryIndexer { get; }
|
||||
public GlobalSpace GlobalSpace { get; }
|
||||
public IDaoFactory DaoFactory { get; }
|
||||
public ProviderFolderDao ProviderFolderDao { get; }
|
||||
public CrossDao CrossDao { get; }
|
||||
|
||||
public FolderDao(
|
||||
FactoryIndexer<FoldersWrapper> factoryIndexer,
|
||||
FactoryIndexer<DbFolder> factoryIndexer,
|
||||
UserManager userManager,
|
||||
DbContextManager<FilesDbContext> dbContextManager,
|
||||
TenantManager tenantManager,
|
||||
@ -318,6 +317,8 @@ namespace ASC.Files.Core.Data
|
||||
toUpdate.ModifiedBy = folder.ModifiedBy;
|
||||
|
||||
FilesDbContext.SaveChanges();
|
||||
|
||||
FactoryIndexer.IndexAsync(toUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -337,6 +338,7 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
newFolder = FilesDbContext.Folders.Add(newFolder).Entity;
|
||||
FilesDbContext.SaveChanges();
|
||||
FactoryIndexer.IndexAsync(newFolder);
|
||||
folder.ID = newFolder.Id;
|
||||
|
||||
//itself link
|
||||
@ -380,7 +382,7 @@ namespace ASC.Files.Core.Data
|
||||
RecalculateFoldersCount(folder.ID);
|
||||
}
|
||||
|
||||
FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
|
||||
//FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
|
||||
return folder.ID;
|
||||
}
|
||||
|
||||
@ -413,6 +415,11 @@ namespace ASC.Files.Core.Data
|
||||
var folderToDelete = Query(FilesDbContext.Folders).Where(r => subfolders.Any(a => r.Id == a));
|
||||
FilesDbContext.Folders.RemoveRange(folderToDelete);
|
||||
|
||||
foreach (var f in folderToDelete)
|
||||
{
|
||||
FactoryIndexer.DeleteAsync(f);
|
||||
}
|
||||
|
||||
var treeToDelete = FilesDbContext.Tree.Where(r => subfolders.Any(a => r.FolderId == a));
|
||||
FilesDbContext.Tree.RemoveRange(treeToDelete);
|
||||
|
||||
@ -445,7 +452,7 @@ namespace ASC.Files.Core.Data
|
||||
RecalculateFoldersCount(parent);
|
||||
}
|
||||
|
||||
FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = id });
|
||||
//FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = id });
|
||||
}
|
||||
|
||||
public TTo MoveFolder<TTo>(int folderId, TTo toFolderId, CancellationToken? cancellationToken)
|
||||
@ -574,7 +581,7 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
copy = GetFolder(SaveFolder(copy));
|
||||
|
||||
FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, copy));
|
||||
//FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, copy));
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ -673,6 +680,8 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
FilesDbContext.SaveChanges();
|
||||
|
||||
FactoryIndexer.IndexAsync(toUpdate);
|
||||
|
||||
return folder.ID;
|
||||
}
|
||||
|
||||
@ -958,7 +967,7 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
#endregion
|
||||
|
||||
protected IQueryable<DbFolder> GetFolderQuery(Expression<Func<DbFolder, bool>> where = null)
|
||||
protected internal IQueryable<DbFolder> GetFolderQuery(Expression<Func<DbFolder, bool>> where = null)
|
||||
{
|
||||
var q = Query(FilesDbContext.Folders);
|
||||
if (where != null)
|
||||
@ -1154,7 +1163,7 @@ namespace ASC.Files.Core.Data
|
||||
services.TryAddTransient<Folder<string>>();
|
||||
|
||||
return services
|
||||
.AddFactoryIndexerService<FoldersWrapper>()
|
||||
.AddFactoryIndexerService<DbFolder>()
|
||||
.AddTenantManagerService()
|
||||
.AddUserManagerService()
|
||||
.AddFilesDbContextService()
|
||||
|
@ -1,14 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.ElasticSearch;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using Nest;
|
||||
|
||||
using ColumnAttribute = System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
|
||||
|
||||
namespace ASC.Files.Core.EF
|
||||
{
|
||||
public static class Tables
|
||||
{
|
||||
public const string File = "file";
|
||||
public const string Tree = "tree";
|
||||
public const string Folder = "folder";
|
||||
}
|
||||
|
||||
[ElasticsearchType(RelationName = Tables.File)]
|
||||
[Table("files_file")]
|
||||
public class DbFile : BaseEntity, IDbFile, IDbSearch
|
||||
public class DbFile : BaseEntity, IDbFile, IDbSearch, ISearchItemDocument
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Version { get; set; }
|
||||
@ -22,6 +37,7 @@ namespace ASC.Files.Core.EF
|
||||
[Column("folder_id")]
|
||||
public int FolderId { get; set; }
|
||||
|
||||
[Text(Analyzer = "whitespacecustom")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[Column("content_length")]
|
||||
@ -50,12 +66,30 @@ namespace ASC.Files.Core.EF
|
||||
|
||||
[Column("converted_type")]
|
||||
public string ConvertedType { get; set; }
|
||||
|
||||
public string Comment { get; set; }
|
||||
public string Changes { get; set; }
|
||||
public bool Encrypted { get; set; }
|
||||
public ForcesaveType Forcesave { get; set; }
|
||||
|
||||
|
||||
[Nested]
|
||||
[NotMapped]
|
||||
public List<DbFolderTree> Folders { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string IndexName
|
||||
{
|
||||
get => Tables.File;
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public Document Document { get; set; }
|
||||
|
||||
public Expression<Func<ISearchItem, object[]>> SearchContentFields
|
||||
{
|
||||
get => (a) => new[] { Title, Comment, Changes, Document.Attachment.Content };
|
||||
}
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { TenantId, Id, Version };
|
||||
|
@ -27,7 +27,7 @@ namespace ASC.Files.Core.EF
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { TenantId, EntryType, EntryId, Owner };
|
||||
return new object[] { TenantId, EntryId, EntryType, Subject };
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ namespace ASC.Files.Core.EF
|
||||
public static ModelBuilder AddDbFilesSecurity(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<DbFilesSecurity>()
|
||||
.HasKey(c => new { c.TenantId, c.EntryType, c.EntryId, c.Owner });
|
||||
.HasKey(c => new { c.TenantId, c.EntryId, c.EntryType, c.Subject });
|
||||
|
||||
return modelBuilder;
|
||||
}
|
||||
|
@ -1,16 +1,25 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using ASC.ElasticSearch;
|
||||
|
||||
using Nest;
|
||||
|
||||
using ColumnAttribute = System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
|
||||
|
||||
namespace ASC.Files.Core.EF
|
||||
{
|
||||
[ElasticsearchType(RelationName = Tables.Folder)]
|
||||
[Table("files_folder")]
|
||||
public class DbFolder : IDbFile, IDbSearch
|
||||
public class DbFolder : IDbFile, IDbSearch, ISearchItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("parent_id")]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
[Text(Analyzer = "whitespacecustom")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[Column("folder_type")]
|
||||
@ -32,5 +41,19 @@ namespace ASC.Files.Core.EF
|
||||
public int TenantId { get; set; }
|
||||
public int FoldersCount { get; set; }
|
||||
public int FilesCount { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string IndexName
|
||||
{
|
||||
get => Tables.Folder;
|
||||
}
|
||||
|
||||
public Expression<Func<ISearchItem, object[]>> SearchContentFields
|
||||
{
|
||||
get
|
||||
{
|
||||
return (a) => new[] { Title };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,12 @@ using ASC.Core.Common.EF;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using Nest;
|
||||
|
||||
namespace ASC.Files.Core.EF
|
||||
{
|
||||
|
||||
[ElasticsearchType(RelationName = Tables.Tree)]
|
||||
[Table("files_folder_tree")]
|
||||
public class DbFolderTree : BaseEntity
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
using ASC.Common;
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@ -18,6 +19,7 @@ namespace ASC.Files.Core.EF
|
||||
public DbSet<DbFilesTag> Tag { get; set; }
|
||||
public DbSet<DbFilesThirdpartyApp> ThirdpartyApp { get; set; }
|
||||
public DbSet<DbEncryptedData> EncryptedData { get; set; }
|
||||
public DbSet<DbTenant> Tenants { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@ -29,7 +31,8 @@ namespace ASC.Files.Core.EF
|
||||
.AddDbFilesThirdpartyIdMapping()
|
||||
.AddDbFilesTagLink()
|
||||
.AddDbFilesThirdpartyApp()
|
||||
.AddDbEncryptedData();
|
||||
.AddDbEncryptedData()
|
||||
.AddDbTenant();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ using ASC.ElasticSearch;
|
||||
using ASC.FederatedLogin.LoginProviders;
|
||||
using ASC.Files.Core;
|
||||
using ASC.Files.Core.Data;
|
||||
using ASC.Files.Core.EF;
|
||||
using ASC.Files.Core.Security;
|
||||
using ASC.Files.Resources;
|
||||
using ASC.MessagingSystem;
|
||||
@ -81,8 +82,8 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
public FilesSettingsHelper FilesSettingsHelper { get; }
|
||||
public AuthContext AuthContext { get; }
|
||||
public UserManager UserManager { get; }
|
||||
public FactoryIndexer<FoldersWrapper> FoldersIndexer { get; }
|
||||
public FactoryIndexer<FilesWrapper> FilesIndexer { get; }
|
||||
public FactoryIndexer<DbFolder> FoldersIndexer { get; }
|
||||
public FactoryIndexer<DbFile> FilesIndexer { get; }
|
||||
public FileUtility FileUtility { get; }
|
||||
public FilesLinkUtility FilesLinkUtility { get; }
|
||||
public BaseCommonLinkUtility BaseCommonLinkUtility { get; }
|
||||
@ -123,8 +124,8 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
FilesSettingsHelper filesSettingsHelper,
|
||||
AuthContext authContext,
|
||||
UserManager userManager,
|
||||
FactoryIndexer<FoldersWrapper> foldersIndexer,
|
||||
FactoryIndexer<FilesWrapper> filesIndexer,
|
||||
FactoryIndexer<DbFolder> foldersIndexer,
|
||||
FactoryIndexer<DbFile> filesIndexer,
|
||||
FileUtility fileUtility,
|
||||
FilesLinkUtility filesLinkUtility,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility,
|
||||
@ -415,10 +416,10 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
|
||||
FilesMessageService.Send(folder, GetHttpHeaders(), MessageAction.FolderRenamed, folder.Title);
|
||||
|
||||
if (!folder.ProviderEntry)
|
||||
{
|
||||
FoldersIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
|
||||
}
|
||||
//if (!folder.ProviderEntry)
|
||||
//{
|
||||
// FoldersIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
|
||||
//}
|
||||
}
|
||||
|
||||
var tag = tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folder).FirstOrDefault();
|
||||
@ -745,10 +746,10 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
{
|
||||
FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRenamed, file.Title);
|
||||
|
||||
if (!file.ProviderEntry)
|
||||
{
|
||||
FilesIndexer.UpdateAsync(FilesWrapper.GetFilesWrapper(ServiceProvider, file), true, r => r.Title);
|
||||
}
|
||||
//if (!file.ProviderEntry)
|
||||
//{
|
||||
// FilesIndexer.UpdateAsync(FilesWrapper.GetFilesWrapper(ServiceProvider, file), true, r => r.Title);
|
||||
//}
|
||||
}
|
||||
|
||||
if (file.RootFolderType == FolderType.USER
|
||||
@ -2061,8 +2062,8 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
.AddGlobalFolderHelperService()
|
||||
.AddAuthContextService()
|
||||
.AddUserManagerService()
|
||||
.AddFoldersWrapperService()
|
||||
.AddFilesWrapperService()
|
||||
.AddFactoryIndexerFolderService()
|
||||
.AddFactoryIndexerFileService()
|
||||
.AddFilesLinkUtilityService()
|
||||
.AddBaseCommonLinkUtilityService()
|
||||
.AddCoreBaseSettingsService()
|
||||
|
127
products/ASC.Files/Server/Core/Search/FactoryIndexerFile.cs
Normal file
127
products/ASC.Files/Server/Core/Search/FactoryIndexerFile.cs
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.ElasticSearch;
|
||||
using ASC.ElasticSearch.Core;
|
||||
using ASC.Files.Core;
|
||||
using ASC.Files.Core.Data;
|
||||
using ASC.Files.Core.EF;
|
||||
using ASC.Files.Resources;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Web.Files.Core.Search
|
||||
{
|
||||
public class FactoryIndexerFile : FactoryIndexer<DbFile>
|
||||
{
|
||||
public IDaoFactory DaoFactory { get; }
|
||||
|
||||
public FactoryIndexerFile(
|
||||
IOptionsMonitor<ILog> options,
|
||||
TenantManager tenantManager,
|
||||
SearchSettingsHelper searchSettingsHelper,
|
||||
FactoryIndexer factoryIndexer,
|
||||
BaseIndexer<DbFile> baseIndexer,
|
||||
IServiceProvider serviceProvider,
|
||||
IDaoFactory daoFactory)
|
||||
: base(options, tenantManager, searchSettingsHelper, factoryIndexer, baseIndexer, serviceProvider)
|
||||
{
|
||||
DaoFactory = daoFactory;
|
||||
}
|
||||
|
||||
public override void IndexAll()
|
||||
{
|
||||
var fileDao = DaoFactory.GetFileDao<int>() as FileDao;
|
||||
|
||||
(int, int, int) getCount(DateTime lastIndexed)
|
||||
{
|
||||
var q = fileDao.FilesDbContext.Files
|
||||
.Where(r => r.ModifiedOn >= lastIndexed)
|
||||
.Where(r => r.CurrentVersion)
|
||||
.Join(fileDao.FilesDbContext.Tenants, r => r.TenantId, r => r.Id, (f, t) => new { f, t })
|
||||
.Where(r => r.t.Status == ASC.Core.Tenants.TenantStatus.Active);
|
||||
|
||||
var count = q.GroupBy(a => a.f.Id).Count();
|
||||
var min = count > 0 ? q.Min(r => r.f.Id) : 0;
|
||||
var max = count > 0 ? q.Max(r => r.f.Id) : 0;
|
||||
|
||||
return (count, max, min);
|
||||
}
|
||||
|
||||
List<DbFile> getData(long i, long step, DateTime lastIndexed) =>
|
||||
fileDao.FilesDbContext.Files
|
||||
.Where(r => r.ModifiedOn >= lastIndexed)
|
||||
.Where(r => r.CurrentVersion)
|
||||
.Where(r => r.Id >= i && r.Id <= i + step)
|
||||
.Join(fileDao.FilesDbContext.Tenants, r => r.TenantId, r => r.Id, (f, t) => new { f, t })
|
||||
.Where(r => r.t.Status == ASC.Core.Tenants.TenantStatus.Active)
|
||||
.Select(r => r.f)
|
||||
.ToList();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var data in Indexer.IndexAll(getCount, getData))
|
||||
{
|
||||
data.ForEach(r =>
|
||||
{
|
||||
TenantManager.SetCurrentTenant(r.TenantId);
|
||||
fileDao.InitDocument(r);
|
||||
TenantManager.CurrentTenant = null;
|
||||
});
|
||||
Index(data);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string SettingsTitle
|
||||
{
|
||||
get { return FilesCommonResource.IndexTitle; }
|
||||
}
|
||||
}
|
||||
public static class FactoryIndexerFileExtention
|
||||
{
|
||||
public static DIHelper AddFactoryIndexerFileService(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<DbFile>();
|
||||
services.TryAddScoped<FactoryIndexer<DbFile>, FactoryIndexerFile>();
|
||||
|
||||
return services
|
||||
.AddFactoryIndexerService<DbFile>(false);
|
||||
}
|
||||
}
|
||||
}
|
116
products/ASC.Files/Server/Core/Search/FactoryIndexerFolder.cs
Normal file
116
products/ASC.Files/Server/Core/Search/FactoryIndexerFolder.cs
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.ElasticSearch;
|
||||
using ASC.ElasticSearch.Core;
|
||||
using ASC.Files.Core;
|
||||
using ASC.Files.Core.Data;
|
||||
using ASC.Files.Core.EF;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Web.Files.Core.Search
|
||||
{
|
||||
public class FactoryIndexerFolder : FactoryIndexer<DbFolder>
|
||||
{
|
||||
public IDaoFactory DaoFactory { get; }
|
||||
|
||||
public FactoryIndexerFolder(
|
||||
IOptionsMonitor<ILog> options,
|
||||
TenantManager tenantManager,
|
||||
SearchSettingsHelper searchSettingsHelper,
|
||||
FactoryIndexer factoryIndexer,
|
||||
BaseIndexer<DbFolder> baseIndexer,
|
||||
IServiceProvider serviceProvider,
|
||||
IDaoFactory daoFactory)
|
||||
: base(options, tenantManager, searchSettingsHelper, factoryIndexer, baseIndexer, serviceProvider)
|
||||
{
|
||||
DaoFactory = daoFactory;
|
||||
}
|
||||
|
||||
public override void IndexAll()
|
||||
{
|
||||
var folderDao = DaoFactory.GetFolderDao<int>() as FolderDao;
|
||||
|
||||
(int, int, int) getCount(DateTime lastIndexed)
|
||||
{
|
||||
var q =
|
||||
folderDao.FilesDbContext.Folders
|
||||
.Where(r => r.ModifiedOn >= lastIndexed)
|
||||
.Join(folderDao.FilesDbContext.Tenants, r => r.TenantId, r => r.Id, (f, t) => new { f, t })
|
||||
.Where(r => r.t.Status == ASC.Core.Tenants.TenantStatus.Active);
|
||||
|
||||
var count = q.GroupBy(a => a.f.Id).Count();
|
||||
var min = count > 0 ? q.Min(r => r.f.Id) : 0;
|
||||
var max = count > 0 ? q.Max(r => r.f.Id) : 0;
|
||||
|
||||
return (count, max, min);
|
||||
}
|
||||
|
||||
List<DbFolder> getData(long i, long step, DateTime lastIndexed) =>
|
||||
folderDao.FilesDbContext.Folders
|
||||
.Where(r => r.ModifiedOn >= lastIndexed)
|
||||
.Where(r => r.Id >= i && r.Id <= i + step)
|
||||
.Join(folderDao.FilesDbContext.Tenants, r => r.TenantId, r => r.Id, (f, t) => new { f, t })
|
||||
.Where(r => r.t.Status == ASC.Core.Tenants.TenantStatus.Active)
|
||||
.Select(r => r.f)
|
||||
.ToList();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var data in Indexer.IndexAll(getCount, getData))
|
||||
{
|
||||
Index(data);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FactoryIndexerFolderExtention
|
||||
{
|
||||
public static DIHelper AddFactoryIndexerFolderService(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<DbFolder>();
|
||||
services.TryAddScoped<FactoryIndexer<DbFolder>, FactoryIndexerFolder>();
|
||||
|
||||
return services
|
||||
.AddFactoryIndexerService<DbFolder>(false)
|
||||
.AddDaoFactoryService();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
using ASC.ElasticSearch;
|
||||
using ASC.ElasticSearch.Core;
|
||||
using ASC.Files.Core;
|
||||
using ASC.Files.Core.Data;
|
||||
using ASC.Files.Resources;
|
||||
using ASC.Web.Core.Files;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ASC.Web.Files.Core.Search
|
||||
{
|
||||
public sealed class FilesWrapper : WrapperWithDoc
|
||||
{
|
||||
[Column("title", 1)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[ColumnLastModified("modified_on")]
|
||||
public override DateTime LastModifiedOn { get; set; }
|
||||
|
||||
[ColumnMeta("version", 2)]
|
||||
public int Version { get; set; }
|
||||
|
||||
[ColumnCondition("current_version", 3, true)]
|
||||
public bool Current { get; set; }
|
||||
|
||||
[ColumnMeta("encrypted", 4)]
|
||||
public bool Encrypted { get; set; }
|
||||
|
||||
[ColumnMeta("content_length", 5)]
|
||||
public long ContentLength { get; set; }
|
||||
|
||||
[ColumnMeta("create_by", 6)]
|
||||
public Guid CreateBy { get; set; }
|
||||
|
||||
[ColumnMeta("create_on", 7)]
|
||||
public DateTime CreateOn { get; set; }
|
||||
|
||||
[ColumnMeta("category", 8)]
|
||||
public int Category { get; set; }
|
||||
|
||||
|
||||
[Join(JoinTypeEnum.Sub, "folder_id:folder_id")]
|
||||
public List<FilesFoldersWrapper> Folders { get; set; }
|
||||
|
||||
protected override string Table { get { return "files_file"; } }
|
||||
|
||||
|
||||
public FilesWrapper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public FilesWrapper(IServiceProvider serviceProvider, TenantManager tenantManager, FileUtility fileUtility, IDaoFactory daoFactory)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
TenantManager = tenantManager;
|
||||
FileUtility = fileUtility;
|
||||
DaoFactory = daoFactory;
|
||||
}
|
||||
|
||||
public static FilesWrapper GetFilesWrapper<T>(IServiceProvider serviceProvider, File<T> d, List<int> parentFolders = null)
|
||||
{
|
||||
var wrapper = serviceProvider.GetService<FilesWrapper>();
|
||||
var tenantManager = serviceProvider.GetService<TenantManager>();
|
||||
|
||||
wrapper.Id = Convert.ToInt32(d.ID);
|
||||
wrapper.Title = d.Title;
|
||||
wrapper.Version = d.Version;
|
||||
wrapper.Encrypted = d.Encrypted;
|
||||
wrapper.ContentLength = d.ContentLength;
|
||||
wrapper.LastModifiedOn = d.ModifiedOn;
|
||||
wrapper.TenantId = tenantManager.GetCurrentTenant().TenantId;
|
||||
|
||||
if (parentFolders != null)
|
||||
{
|
||||
wrapper.Folders = parentFolders.Select(r => new FilesFoldersWrapper { FolderId = r.ToString() }).ToList();
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
protected override Stream GetDocumentStream()
|
||||
{
|
||||
TenantManager.SetCurrentTenant(TenantId);
|
||||
|
||||
if (Encrypted) return null;
|
||||
if (!FileUtility.CanIndex(Title)) return null;
|
||||
|
||||
var fileDao = DaoFactory.GetFileDao<int>();
|
||||
var file = ServiceProvider.GetService<File<int>>();
|
||||
file.ID = Id;
|
||||
file.Title = Title;
|
||||
file.Version = Version;
|
||||
file.ContentLength = ContentLength;
|
||||
|
||||
if (!fileDao.IsExistOnStorage(file)) return null;
|
||||
if (file.ContentLength > MaxContentLength) return null;
|
||||
|
||||
return fileDao.GetFileStream(file);
|
||||
}
|
||||
|
||||
public override string SettingsTitle
|
||||
{
|
||||
get { return FilesCommonResource.IndexTitle; }
|
||||
}
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private TenantManager TenantManager { get; }
|
||||
private FileUtility FileUtility { get; }
|
||||
private IDaoFactory DaoFactory { get; }
|
||||
}
|
||||
|
||||
public sealed class FilesFoldersWrapper : Wrapper
|
||||
{
|
||||
[Column("parent_id", 1)]
|
||||
public string FolderId { get; set; }
|
||||
|
||||
[ColumnId("")]
|
||||
public override int Id { get; set; }
|
||||
|
||||
[ColumnTenantId("")]
|
||||
public override int TenantId { get; set; }
|
||||
|
||||
[ColumnLastModified("")]
|
||||
public override DateTime LastModifiedOn { get; set; }
|
||||
|
||||
protected override string Table { get { return "files_folder_tree"; } }
|
||||
}
|
||||
|
||||
public static class FilesWrapperExtention
|
||||
{
|
||||
public static DIHelper AddFilesWrapperService(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<FilesWrapper>();
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
.AddFileUtilityService()
|
||||
.AddDaoFactoryService()
|
||||
.AddFactoryIndexerService<FilesWrapper>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
using ASC.ElasticSearch;
|
||||
using ASC.Files.Core;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ASC.Web.Files.Core.Search
|
||||
{
|
||||
public sealed class FoldersWrapper : Wrapper
|
||||
{
|
||||
[Column("title", 1)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[ColumnLastModified("modified_on")]
|
||||
public override DateTime LastModifiedOn { get; set; }
|
||||
|
||||
protected override string Table { get { return "files_folder"; } }
|
||||
|
||||
public static FoldersWrapper GetFolderWrapper<T>(IServiceProvider serviceProvider, Folder<T> d)
|
||||
{
|
||||
var tenantManager = serviceProvider.GetService<TenantManager>();
|
||||
|
||||
return new FoldersWrapper
|
||||
{
|
||||
Id = Convert.ToInt32(d.ID),
|
||||
Title = d.Title,
|
||||
TenantId = tenantManager.GetCurrentTenant().TenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
public static class FoldersWrapperExtention
|
||||
{
|
||||
public static DIHelper AddFoldersWrapperService(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<FoldersWrapper>();
|
||||
return services
|
||||
.AddFactoryIndexerService<FoldersWrapper>();
|
||||
}
|
||||
}
|
||||
}
|
@ -73,11 +73,13 @@ namespace ASC.Files.Thirdparty
|
||||
|
||||
internal class ProviderAccountDao : IProviderDao
|
||||
{
|
||||
protected int TenantID { get; private set; }
|
||||
private int tenantID;
|
||||
protected int TenantID { get => tenantID != 0 ? tenantID : (tenantID = TenantManager.GetCurrentTenant().TenantId); }
|
||||
public FilesDbContext FilesDbContext { get; }
|
||||
public ILog Logger { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public TenantUtil TenantUtil { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public InstanceCrypto InstanceCrypto { get; }
|
||||
public SecurityContext SecurityContext { get; }
|
||||
public ConsumerFactory ConsumerFactory { get; }
|
||||
@ -92,11 +94,11 @@ namespace ASC.Files.Thirdparty
|
||||
DbContextManager<FilesDbContext> dbContextManager,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
TenantID = tenantManager.GetCurrentTenant().TenantId;
|
||||
FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId);
|
||||
Logger = options.Get("ASC.Files");
|
||||
ServiceProvider = serviceProvider;
|
||||
TenantUtil = tenantUtil;
|
||||
TenantManager = tenantManager;
|
||||
InstanceCrypto = instanceCrypto;
|
||||
SecurityContext = securityContext;
|
||||
ConsumerFactory = consumerFactory;
|
||||
|
@ -49,7 +49,8 @@ namespace ASC.Files.Thirdparty.ProviderDao
|
||||
{
|
||||
private readonly List<IDaoSelector> Selectors;
|
||||
|
||||
private int TenantID { get; set; }
|
||||
private int tenantID;
|
||||
private int TenantID { get => tenantID != 0 ? tenantID : (tenantID = TenantManager.GetCurrentTenant().TenantId); }
|
||||
|
||||
public ProviderDaoBase(
|
||||
IServiceProvider serviceProvider,
|
||||
@ -59,10 +60,10 @@ namespace ASC.Files.Thirdparty.ProviderDao
|
||||
CrossDao crossDao)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
TenantManager = tenantManager;
|
||||
SecurityDao = securityDao;
|
||||
TagDao = tagDao;
|
||||
CrossDao = crossDao;
|
||||
TenantID = tenantManager.GetCurrentTenant().TenantId;
|
||||
|
||||
Selectors = new List<IDaoSelector>
|
||||
{
|
||||
@ -77,6 +78,7 @@ namespace ASC.Files.Thirdparty.ProviderDao
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public SecurityDao<string> SecurityDao { get; }
|
||||
public TagDao<string> TagDao { get; }
|
||||
public CrossDao CrossDao { get; }
|
||||
|
@ -18,10 +18,10 @@ namespace ASC.Files.Model
|
||||
|
||||
public class DownloadModel : BaseBatchModel<object>
|
||||
{
|
||||
public IEnumerable<ItemKeyValuePair<string, string>> FileConvertIds { get; set; }
|
||||
public IEnumerable<ItemKeyValuePair<object, string>> FileConvertIds { get; set; }
|
||||
public DownloadModel() : base()
|
||||
{
|
||||
FileConvertIds = new List<ItemKeyValuePair<string, string>>();
|
||||
FileConvertIds = new List<ItemKeyValuePair<object, string>>();
|
||||
}
|
||||
}
|
||||
|
||||
|
15
products/ASC.Files/Service/ASC.Files.Service.csproj
Normal file
15
products/ASC.Files/Service/ASC.Files.Service.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ASC.Common\ASC.Common.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\services\ASC.ElasticSearch\ASC.ElasticSearch.csproj" />
|
||||
<ProjectReference Include="..\Server\ASC.Files.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
77
products/ASC.Files/Service/Program.cs
Normal file
77
products/ASC.Files/Service/Program.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Common.DependencyInjection;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.ElasticSearch;
|
||||
using ASC.Web.Files.Core.Search;
|
||||
using ASC.Web.Files.Utils;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ASC.Files.Service
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var host = Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((hostContext, config) =>
|
||||
{
|
||||
var buided = config.Build();
|
||||
var path = buided["pathToConf"];
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
path = Path.GetFullPath(Path.Combine(hostContext.HostingEnvironment.ContentRootPath, path));
|
||||
}
|
||||
config.SetBasePath(path);
|
||||
var env = hostContext.Configuration.GetValue("ENVIRONMENT", "Production");
|
||||
config
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{"pathToConf", path }
|
||||
}
|
||||
)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env}.json", true)
|
||||
.AddJsonFile($"appsettings.services.json", true)
|
||||
.AddJsonFile("storage.json")
|
||||
.AddJsonFile("notify.json")
|
||||
.AddJsonFile("kafka.json")
|
||||
.AddJsonFile($"kafka.{env}.json", true)
|
||||
.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
var diHelper = new DIHelper(services);
|
||||
diHelper.AddNLogManager("ASC.Files");
|
||||
services.AddHostedService<ServiceLauncher>();
|
||||
diHelper
|
||||
.AddServiceLauncher()
|
||||
.AddFileConverterService()
|
||||
.AddKafkaService()
|
||||
.AddFactoryIndexerFileService()
|
||||
.AddFactoryIndexerFolderService();
|
||||
|
||||
var a = typeof(FactoryIndexer<ISearchItem>).ToString();
|
||||
services.AddAutofac(hostContext.Configuration, hostContext.HostingEnvironment.ContentRootPath, "search.json");
|
||||
})
|
||||
.UseConsoleLifetime()
|
||||
.Build();
|
||||
|
||||
using (host)
|
||||
{
|
||||
// Start the host
|
||||
await host.StartAsync();
|
||||
|
||||
// Wait for the host to shutdown
|
||||
await host.WaitForShutdownAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
products/ASC.Files/Service/Properties/launchSettings.json
Normal file
33
products/ASC.Files/Service/Properties/launchSettings.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:5009",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": false,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "files.service",
|
||||
"log__dir": "../../../Logs"
|
||||
}
|
||||
},
|
||||
"ASC.Files.Service": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5009",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "files.service",
|
||||
"log__dir": "../../../Logs"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
products/ASC.Files/Service/appsettings.json
Normal file
3
products/ASC.Files/Service/appsettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"pathToConf": "..\\..\\..\\config"
|
||||
}
|
22
products/ASC.Files/Service/search.json
Normal file
22
products/ASC.Files/Service/search.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"type": "ASC.Web.Files.Core.Search.FactoryIndexerFolder, ASC.Files",
|
||||
"services": [
|
||||
{
|
||||
"type": "ASC.ElasticSearch.IFactoryIndexer, ASC.ElasticSearch"
|
||||
}
|
||||
],
|
||||
"instanceScope": "perlifetimescope"
|
||||
},
|
||||
{
|
||||
"type": "ASC.Web.Files.Core.Search.FactoryIndexerFile, ASC.Files",
|
||||
"services": [
|
||||
{
|
||||
"type": "ASC.ElasticSearch.IFactoryIndexer, ASC.ElasticSearch"
|
||||
}
|
||||
],
|
||||
"instanceScope": "perlifetimescope"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.IO
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
|
||||
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context
|
||||
{
|
||||
internal class OAuthServiceContext
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token;
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token
|
||||
namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token
|
||||
{
|
||||
/// <summary>
|
||||
/// The OAuthToken will be generated during the login process in a oauth compliant
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox
|
||||
{
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API
|
||||
{
|
||||
internal class GenericHelper
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using AppLimit.CloudComputing.SharpBox.Exceptions;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.API;
|
||||
using System.Threading;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.API;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet.Logic
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.Json;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.Json;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox
|
||||
{
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class of all credentials
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox
|
||||
{
|
||||
internal static class DropBoxResourceIDHelpers
|
||||
{
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.Json;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Extensions;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.IO;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.API;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.API;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.API;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token;
|
||||
using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects;
|
||||
using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects;
|
||||
|
||||
namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive
|
||||
{
|
||||
|
@ -25,10 +25,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using ASC.Common.Security.Authentication;
|
||||
using ASC.Core;
|
||||
using ASC.Notify.Patterns;
|
||||
using ASC.Web.Core.Users;
|
||||
|
||||
namespace ASC.Web.Studio.Core.Notify
|
||||
{
|
||||
|
@ -43,8 +43,6 @@ using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Data.Storage;
|
||||
using ASC.Web.Core.Utility.Skins;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Web.Core.Users
|
||||
|
@ -105,7 +105,7 @@ namespace ASC.Web.Core
|
||||
get { return new Guid("{46CFA73A-F320-46CF-8D5B-CD82E1D67F26}"); }
|
||||
}
|
||||
|
||||
public IContainer Container { get; }
|
||||
public ILifetimeScope Container { get; }
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public IWebItem this[Guid id]
|
||||
@ -126,8 +126,17 @@ namespace ASC.Web.Core
|
||||
LoadItems();
|
||||
}
|
||||
|
||||
public WebItemManager(ILifetimeScope container, IConfiguration configuration, IOptionsMonitor<ILog> options)
|
||||
: this(null, configuration, options)
|
||||
{
|
||||
Container = container;
|
||||
LoadItems();
|
||||
}
|
||||
|
||||
public void LoadItems()
|
||||
{
|
||||
if (Container == null) return;
|
||||
|
||||
foreach (var webitem in Container.Resolve<IEnumerable<IWebItem>>())
|
||||
{
|
||||
var file = webitem.ID.ToString();
|
||||
|
Loading…
Reference in New Issue
Block a user