Merge branch 'develop' into feature/archived-redesign-empty-screen

This commit is contained in:
Vlada Gazizova 2022-09-19 09:55:07 +03:00
commit ae0eb0a143
208 changed files with 2874 additions and 2792 deletions

View File

@ -1,4 +1,4 @@
@echo off
PUSHD %~dp0..\..
set servicepath=%cd%\web\ASC.Web.Api\bin\Debug\ASC.Web.Api.exe urls=http://0.0.0.0:5000 $STORAGE_ROOT=%cd%\Data log:dir=%cd%\Logs log:name=api pathToConf=%cd%\config core:products:folder=%cd%\products
set servicepath=%cd%\web\ASC.Web.Api\bin\Debug\ASC.Web.Api.exe urls=http://0.0.0.0:5000 $STORAGE_ROOT=%cd%\Data log:dir=%cd%\Logs log:name=web.api pathToConf=%cd%\config core:products:folder=%cd%\products

View File

@ -1,4 +1,4 @@
@echo off
PUSHD %~dp0..\..
set servicepath=%cd%\web\ASC.Web.Studio\bin\Debug\ASC.Web.Studio.exe urls=http://0.0.0.0:5003 $STORAGE_ROOT=%cd%\Data log:dir=%cd%\Logs log:name=studio pathToConf=%cd%\config core:products:folder=%cd%\products
set servicepath=%cd%\web\ASC.Web.Studio\bin\Debug\ASC.Web.Studio.exe urls=http://0.0.0.0:5003 $STORAGE_ROOT=%cd%\Data log:dir=%cd%\Logs log:name=web.studio pathToConf=%cd%\config core:products:folder=%cd%\products

View File

@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.7" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.1.0" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.1.4" />
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="8.0.4" />
<PackageReference Include="StackExchange.Redis.Extensions.Newtonsoft" Version="8.0.4" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" />

View File

@ -273,35 +273,3 @@ public abstract class BaseStartup
}
}
public static class LogNLogConfigureExtenstion
{
private static LoggingConfiguration GetXmlLoggingConfiguration(IHostEnvironment hostEnvironment, IConfiguration configuration)
{
var loggerConfiguration = new XmlLoggingConfiguration(CrossPlatform.PathCombine(configuration["pathToConf"], "nlog.config"));
var settings = new ConfigurationExtension(configuration).GetSetting<NLogSettings>("log");
if (!string.IsNullOrEmpty(settings.Name))
{
loggerConfiguration.Variables["name"] = settings.Name;
}
if (!string.IsNullOrEmpty(settings.Dir))
{
var dir = Path.IsPathRooted(settings.Dir) ? settings.Dir : CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, settings.Dir);
loggerConfiguration.Variables["dir"] = dir.TrimEnd('/').TrimEnd('\\') + Path.DirectorySeparatorChar;
}
return loggerConfiguration;
}
public static IHostBuilder ConfigureNLogLogging(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureLogging((hostBuildexContext, r) =>
{
LogManager.ThrowConfigExceptions = false;
r.AddNLog(GetXmlLoggingConfiguration(hostBuildexContext.HostingEnvironment, hostBuildexContext.Configuration));
});
}
}

View File

@ -47,16 +47,15 @@ public static class ConfigurationManagerExtension
{"pathToConf", path }
});
config.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
.AddJsonFile("storage.json")
.AddJsonFile("kafka.json")
.AddJsonFile($"kafka.{env.EnvironmentName}.json", true)
.AddJsonFile("rabbitmq.json")
.AddJsonFile($"rabbitmq.{env.EnvironmentName}.json", true)
.AddJsonFile("redis.json")
.AddJsonFile($"redis.{env.EnvironmentName}.json", true);
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile("storage.json", optional: false, reloadOnChange: true)
.AddJsonFile("kafka.json", optional: true, reloadOnChange: true)
.AddJsonFile($"kafka.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile("rabbitmq.json", optional: true, reloadOnChange: true)
.AddJsonFile($"rabbitmq.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile("redis.json", optional: true, reloadOnChange: true)
.AddJsonFile($"redis.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return config;
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog.Web;
namespace ASC.Api.Core.Extensions;
public static class HostBuilderExtension
@ -33,8 +35,10 @@ public static class HostBuilderExtension
hostBuilder.UseSystemd();
hostBuilder.UseWindowsService();
hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory());
hostBuilder.ConfigureNLogLogging();
hostBuilder.UseNLog();
return hostBuilder;
}
}
}

View File

@ -0,0 +1,69 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog.AWS.Logger;
namespace ASC.Api.Core.Extensions;
public static class ISetupBuilderExtension
{
public static ISetupBuilder LoadConfiguration(this ISetupBuilder loggingBuilder, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
var conf = new XmlLoggingConfiguration(CrossPlatform.PathCombine(configuration["pathToConf"], "nlog.config"));
var settings = new ConfigurationExtension(configuration).GetSetting<NLogSettings>("log");
if (!string.IsNullOrEmpty(settings.Name))
{
conf.Variables["name"] = settings.Name;
}
if (!string.IsNullOrEmpty(settings.Dir))
{
var dir = Path.IsPathRooted(settings.Dir) ? settings.Dir : CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, settings.Dir);
conf.Variables["dir"] = dir.TrimEnd('/').TrimEnd('\\') + Path.DirectorySeparatorChar;
}
foreach (var targetName in new[] { "aws", "aws_sql" })
{
var awsTarget = conf.FindTargetByName<AWSTarget>(targetName);
if (awsTarget == null) continue;
//hack
if (!string.IsNullOrEmpty(settings.Name))
{
awsTarget.LogGroup = awsTarget.LogGroup.Replace("${var:name}", settings.Name);
}
if (!string.IsNullOrEmpty(settings.AWSSecretAccessKey))
{
awsTarget.Credentials = new Amazon.Runtime.BasicAWSCredentials(settings.AWSAccessKeyId, settings.AWSSecretAccessKey);
}
}
return loggingBuilder.LoadConfiguration(conf);
}
}

View File

@ -29,6 +29,7 @@
<PackageReference Include="ARSoft.Tools.NetStandard.DXSdata" Version="1.0.0" />
<PackageReference Include="Autofac.Configuration" Version="6.0.0" />
<PackageReference Include="AutoMapper" Version="11.0.1" />
<PackageReference Include="AWS.Logger.NLog" Version="3.1.0" />
<PackageReference Include="Confluent.Kafka" Version="1.9.0" />
<PackageReference Include="Google.Protobuf" Version="3.21.4" />
<PackageReference Include="Grpc.Tools" Version="2.47.0">
@ -54,7 +55,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> -->
<PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="NVelocity" Version="1.2.0" />
<PackageReference Include="protobuf-net" Version="3.1.17" />
<PackageReference Include="RabbitMQ.Client" Version="6.4.0" />

View File

@ -30,5 +30,8 @@ namespace ASC.Common.Logging;
public class NLogSettings
{
public string Name { get; set; }
public string Dir { get; set; }
public string Dir { get; set; }
public string AWSAccessKeyId { get; set; }
public string AWSSecretAccessKey {get; set;}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using ASC.Notify;
namespace ASC.Core.Common.Hosting;
[Scope]
@ -48,6 +50,10 @@ public class RegisterInstanceDao<T> : IRegisterInstanceDao<T> where T : IHostedS
if (inst == null)
{
await _instanceRegistrationContext.AddAsync(obj);
}
else
{
_instanceRegistrationContext.Entry(inst).CurrentValues.SetValues(obj);
}
bool saveFailed;

View File

@ -60,7 +60,7 @@ public class RegisterInstanceManager<T> : IRegisterInstanceManager<T> where T :
{
var firstAliceInstance = GetFirstAliveInstance(instances);
if (firstAliceInstance != null && firstAliceInstance.InstanceRegistrationId == instance.InstanceRegistrationId)
if (firstAliceInstance == null || firstAliceInstance.InstanceRegistrationId == instance.InstanceRegistrationId)
{
instance.IsActive = true;
}

View File

@ -72,7 +72,7 @@ public class BackupAjaxHandler
_tempPath = tempPath;
}
public void StartBackup(BackupStorageType storageType, Dictionary<string, string> storageParams, bool backupMail)
public void StartBackup(BackupStorageType storageType, Dictionary<string, string> storageParams)
{
DemandPermissionsBackup();
@ -80,7 +80,6 @@ public class BackupAjaxHandler
{
TenantId = GetCurrentTenantId(),
UserId = _securityContext.CurrentAccount.ID,
BackupMail = backupMail,
StorageType = storageType,
StorageParams = storageParams
};
@ -141,7 +140,7 @@ public class BackupAjaxHandler
return _backupService.GetBackupHistory(GetCurrentTenantId());
}
public void CreateSchedule(BackupStorageType storageType, Dictionary<string, string> storageParams, int backupsStored, CronParams cronParams, bool backupMail)
public void CreateSchedule(BackupStorageType storageType, Dictionary<string, string> storageParams, int backupsStored, CronParams cronParams)
{
DemandPermissionsBackup();
@ -155,7 +154,6 @@ public class BackupAjaxHandler
var scheduleRequest = new CreateScheduleRequest
{
TenantId = _tenantManager.GetCurrentTenant().Id,
BackupMail = backupMail,
Cron = cronParams.ToString(),
NumberOfBackupsStored = backupsStored,
StorageType = storageType,
@ -198,7 +196,6 @@ public class BackupAjaxHandler
StorageType = response.StorageType,
StorageParams = response.StorageParams.ToDictionary(r => r.Key, r => r.Value) ?? new Dictionary<string, string>(),
CronParams = new CronParams(response.Cron),
BackupMail = response.BackupMail.NullIfDefault(),
BackupsStored = response.NumberOfBackupsStored.NullIfDefault(),
LastBackupTime = response.LastBackupTime
};
@ -224,7 +221,6 @@ public class BackupAjaxHandler
var Schedule = new CreateScheduleRequest
{
TenantId = _tenantManager.GetCurrentTenant().Id,
BackupMail = schedule.BackupMail != null && (bool)schedule.BackupMail,
Cron = schedule.CronParams.ToString(),
NumberOfBackupsStored = schedule.BackupsStored == null ? 0 : (int)schedule.BackupsStored,
StorageType = schedule.StorageType,
@ -337,7 +333,7 @@ public class BackupAjaxHandler
#region transfer
public void StartTransfer(string targetRegion, bool notifyUsers, bool transferMail)
public void StartTransfer(string targetRegion, bool notifyUsers)
{
DemandPermissionsTransfer();
@ -347,7 +343,6 @@ public class BackupAjaxHandler
{
TenantId = GetCurrentTenantId(),
TargetRegion = targetRegion,
BackupMail = transferMail,
NotifyUsers = notifyUsers
});
@ -405,7 +400,6 @@ public class BackupAjaxHandler
public BackupStorageType StorageType { get; set; }
public Dictionary<string, string> StorageParams { get; set; }
public CronParams CronParams { get; set; }
public bool? BackupMail { get; set; }
public int? BackupsStored { get; set; }
public DateTime LastBackupTime { get; set; }
}

View File

@ -41,7 +41,6 @@ public class StartBackupRequest
{
public int TenantId { get; set; }
public Guid UserId { get; set; }
public bool BackupMail { get; set; }
public BackupStorageType StorageType { get; set; }
public string StorageBasePath { get; set; }
public Dictionary<string, string> StorageParams { get; set; }
@ -61,7 +60,6 @@ public class StartTransferRequest
public int TenantId { get; set; }
public string TargetRegion { get; set; }
public bool NotifyUsers { get; set; }
public bool BackupMail { get; set; }
}
public class TransferRegion
@ -91,7 +89,6 @@ public class ScheduleResponse
{
public BackupStorageType StorageType { get; set; }
public string StorageBasePath { get; set; }
public bool BackupMail { get; set; }
public int NumberOfBackupsStored { get; set; }
public string Cron { get; set; }
public DateTime LastBackupTime { get; set; }

View File

@ -30,8 +30,6 @@ public class BackupSchedule : BaseEntity
{
public int TenantId { get; set; }
public bool BackupMail { get; set; }
public string Cron { get; set; }
public int BackupsStored { get; set; }
@ -76,11 +74,6 @@ public static class BackupScheduleExtension
.HasColumnType("int(10)")
.ValueGeneratedNever();
entity.Property(e => e.BackupMail)
.HasColumnName("backup_mail")
.HasColumnType("tinyint(1)")
.HasDefaultValueSql("'0'");
entity.Property(e => e.Cron)
.IsRequired()
.HasColumnName("cron")
@ -132,11 +125,6 @@ public static class BackupScheduleExtension
.HasColumnName("tenant_id")
.HasMaxLength(10);
entity.Property(e => e.BackupMail)
.HasColumnName("backup_mail")
.HasMaxLength(10)
.HasDefaultValueSql("'0'");
entity.Property(e => e.Cron)
.IsRequired()
.HasColumnName("cron")

View File

@ -38,14 +38,12 @@ public record BackupRequestIntegrationEvent : IntegrationEvent
int tenantId,
Guid createBy,
Dictionary<string, string> storageParams,
bool backupMail,
bool isScheduled = false,
int backupsStored = 0,
string storageBasePath = "") : base(createBy, tenantId)
{
StorageType = storageType;
StorageParams = storageParams;
BackupMail = backupMail;
IsScheduled = isScheduled;
BackupsStored = backupsStored;
StorageBasePath = storageBasePath;
@ -57,9 +55,6 @@ public record BackupRequestIntegrationEvent : IntegrationEvent
[ProtoMember(2)]
public Dictionary<string, string> StorageParams { get; private init; }
[ProtoMember(3)]
public bool BackupMail { get; private init; }
[ProtoMember(4)]
public bool IsScheduled { get; private init; }

View File

@ -126,7 +126,7 @@ public class BackupService : IBackupService
public void StartTransfer(StartTransferRequest request)
{
var progress = _backupWorker.StartTransfer(request.TenantId, request.TargetRegion, request.BackupMail, request.NotifyUsers);
var progress = _backupWorker.StartTransfer(request.TenantId, request.TargetRegion, request.NotifyUsers);
if (!string.IsNullOrEmpty(progress.Error))
{
throw new FaultException();
@ -209,7 +209,6 @@ public class BackupService : IBackupService
{
TenantId = request.TenantId,
Cron = request.Cron,
BackupMail = request.BackupMail,
BackupsStored = request.NumberOfBackupsStored,
StorageType = request.StorageType,
StorageBasePath = request.StorageBasePath,
@ -231,7 +230,6 @@ public class BackupService : IBackupService
{
StorageType = schedule.StorageType,
StorageBasePath = schedule.StorageBasePath,
BackupMail = schedule.BackupMail,
NumberOfBackupsStored = schedule.BackupsStored,
Cron = schedule.Cron,
LastBackupTime = schedule.LastBackupTime,

View File

@ -209,7 +209,7 @@ public class BackupWorker
}
}
public BackupProgress StartTransfer(int tenantId, string targetRegion, bool transferMail, bool notify)
public BackupProgress StartTransfer(int tenantId, string targetRegion, bool notify)
{
lock (_synchRoot)
{
@ -223,7 +223,7 @@ public class BackupWorker
if (item == null)
{
item = _serviceProvider.GetService<TransferProgressItem>();
item.Init(targetRegion, transferMail, tenantId, TempFolder, _limit, notify, _currentRegion, _configPaths);
item.Init(targetRegion, tenantId, TempFolder, _limit, notify, _currentRegion, _configPaths);
_progressQueue.EnqueueTask(item);
}

View File

@ -54,7 +54,6 @@ namespace ASC.Data.Backup.Services;
[Transient]
public class BackupProgressItem : BaseBackupProgressItem
{
public bool BackupMail { get; set; }
public Dictionary<string, string> StorageParams { get; set; }
public string TempFolder { get; set; }
@ -94,7 +93,6 @@ public class BackupProgressItem : BaseBackupProgressItem
TenantId = schedule.TenantId;
_storageType = schedule.StorageType;
_storageBasePath = schedule.StorageBasePath;
BackupMail = schedule.BackupMail;
StorageParams = JsonConvert.DeserializeObject<Dictionary<string, string>>(schedule.StorageParams);
_isScheduled = isScheduled;
TempFolder = tempFolder;
@ -109,7 +107,6 @@ public class BackupProgressItem : BaseBackupProgressItem
TenantId = request.TenantId;
_storageType = request.StorageType;
_storageBasePath = request.StorageBasePath;
BackupMail = request.BackupMail;
StorageParams = request.StorageParams.ToDictionary(r => r.Key, r => r.Value);
_isScheduled = isScheduled;
TempFolder = tempFolder;
@ -142,11 +139,7 @@ public class BackupProgressItem : BaseBackupProgressItem
{
var backupTask = _backupPortalTask;
backupTask.Init(TenantId, _configPaths[_currentRegion], tempFile, _limit);
if (!BackupMail)
{
backupTask.IgnoreModule(ModuleName.Mail);
}
backupTask.Init(TenantId, _configPaths[_currentRegion], tempFile, _limit);
backupTask.ProgressChanged += (sender, args) =>
{

View File

@ -74,7 +74,6 @@ public class TransferProgressItem : BaseBackupProgressItem
}
public string TargetRegion { get; set; }
public bool TransferMail { get; set; }
public bool Notify { get; set; }
public string TempFolder { get; set; }
public Dictionary<string, string> ConfigPaths { get; set; }
@ -83,7 +82,6 @@ public class TransferProgressItem : BaseBackupProgressItem
public void Init(
string targetRegion,
bool transferMail,
int tenantId,
string tempFolder,
int limit,
@ -93,7 +91,6 @@ public class TransferProgressItem : BaseBackupProgressItem
{
TenantId = tenantId;
TargetRegion = targetRegion;
TransferMail = transferMail;
Notify = notify;
TempFolder = tempFolder;
ConfigPaths = configPaths;
@ -122,11 +119,8 @@ public class TransferProgressItem : BaseBackupProgressItem
{
Percentage = args.Progress;
PublishChanges();
};
if (!TransferMail)
{
transferProgressItem.IgnoreModule(ModuleName.Mail);
}
};
transferProgressItem.RunJob();
Link = GetLink(alias, false);

View File

@ -1,101 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
public class CalendarModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.Calendar;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly RelationInfo[] _tableRelations;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("calendar_calendars", "tenant", "id") {UserIDColumns = new[] {"owner_id"}},
new TableInfo("calendar_calendar_item"),
new TableInfo("calendar_calendar_user") {UserIDColumns = new[] {"user_id"}},
new TableInfo("calendar_events", "tenant", "id")
{
UserIDColumns = new[] {"owner_id"},
DateColumns = new Dictionary<string, bool> {{"start_date", true}, {"end_date", true}}
},
new TableInfo("calendar_event_history", "tenant"),
new TableInfo("calendar_event_item"),
new TableInfo("calendar_event_user") {UserIDColumns = new[] {"user_id"}},
new TableInfo("calendar_notifications", "tenant")
{
UserIDColumns = new[] {"user_id"},
DateColumns = new Dictionary<string, bool> {{"notify_date", true}}
}
};
public CalendarModuleSpecifics(Helpers helpers)
: base(helpers)
{
_tableRelations = new[]
{
new RelationInfo("calendar_calendars", "id", "calendar_calendar_item", "calendar_id"),
new RelationInfo("calendar_calendars", "id", "calendar_calendar_user", "calendar_id"),
new RelationInfo("calendar_calendars", "id", "calendar_events", "calendar_id"),
new RelationInfo("calendar_calendars", "id", "calendar_event_history", "calendar_id"),
new RelationInfo("calendar_events", "id", "calendar_event_history", "event_id"),
new RelationInfo("calendar_events", "id", "calendar_event_item", "event_id"),
new RelationInfo("calendar_events", "id", "calendar_event_user", "event_id"),
new RelationInfo("calendar_events", "id", "calendar_notifications", "event_id"),
new RelationInfo("core_user", "id", "calendar_calendar_item", "item_id", typeof(TenantsModuleSpecifics),
x => Convert.ToInt32(x["is_group"]) == 0),
new RelationInfo("core_group", "id", "calendar_calendar_item", "item_id", typeof(TenantsModuleSpecifics),
x => Convert.ToInt32(x["is_group"]) == 1 && !helpers.IsEmptyOrSystemGroup(Convert.ToString(x["item_id"]))),
new RelationInfo("core_user", "id", "calendar_event_item", "item_id", typeof(TenantsModuleSpecifics),
x => Convert.ToInt32(x["is_group"]) == 0),
new RelationInfo("core_group", "id", "calendar_event_item", "item_id", typeof(TenantsModuleSpecifics),
x => Convert.ToInt32(x["is_group"]) == 1 && !helpers.IsEmptyOrSystemGroup(Convert.ToString(x["item_id"])))
};
}
protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
if (table.Name == "calendar_calendar_item" || table.Name == "calendar_calendar_user")
{
return "inner join calendar_calendars as t1 on t1.id = t.calendar_id where t1.tenant = " + tenantId;
}
if (table.Name == "calendar_event_item" || table.Name == "calendar_event_user")
{
return "inner join calendar_events as t1 on t1.id = t.event_id where t1.tenant = " + tenantId;
}
if (table.Name == "calendar_event_history")
{
return string.Format(
"inner join calendar_calendars as t1 on t1.id = t.calendar_id and t1.tenant = t.tenant inner join calendar_events as t2 on t2.id = t.event_id where t1.tenant = {0} and t2.tenant = {0}",
tenantId);
}
return base.GetSelectCommandConditionText(tenantId, table);
}
}

View File

@ -1,289 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
public class CommunityModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.Community;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("bookmarking_bookmark", "Tenant", "ID")
{
UserIDColumns = new[] {"UserCreatorID"},
DateColumns = new Dictionary<string, bool> {{"Date", false}}
},
new TableInfo("bookmarking_bookmarktag", "tenant"),
new TableInfo("bookmarking_comment", "tenant", "ID", IdType.Guid)
{
UserIDColumns = new[] {"UserID"},
DateColumns = new Dictionary<string, bool> {{"Datetime", false}}
},
new TableInfo("bookmarking_tag", "tenant", "TagID"),
new TableInfo("bookmarking_userbookmark", "tenant", "UserBookmarkID")
{
UserIDColumns = new[] {"UserID"},
DateColumns = new Dictionary<string, bool> {{"DateAdded", false}, {"LastModified", false}}
},
new TableInfo("bookmarking_userbookmarktag", "tenant"),
new TableInfo("blogs_comments", "Tenant", "id", IdType.Guid)
{
UserIDColumns = new[] {"created_by"},
DateColumns = new Dictionary<string, bool> {{"created_when", false}}
},
new TableInfo("blogs_posts", "Tenant", "post_id", IdType.Autoincrement)
{
UserIDColumns = new[] {"created_by"},
DateColumns = new Dictionary<string, bool> {{"created_when", false}, {"LastModified", false}}
},
new TableInfo("blogs_reviewposts", "Tenant")
{
UserIDColumns = new[] {"reviewed_by"},
DateColumns = new Dictionary<string, bool> {{"timestamp", false}}
},
new TableInfo("blogs_tags", "Tenant"),
new TableInfo("events_comment", "Tenant", "id")
{
UserIDColumns = new[] {"Creator"},
DateColumns = new Dictionary<string, bool> {{"Date", false}}
},
new TableInfo("events_feed", "Tenant", "id")
{
UserIDColumns = new[] {"Creator"},
DateColumns = new Dictionary<string, bool> {{"Date", false}, {"LastModified", false}}
},
new TableInfo("events_poll", "Tenant")
{
DateColumns = new Dictionary<string, bool> {{"StartDate", true}, {"EndDate", true}}
},
new TableInfo("events_pollanswer", "Tenant") {UserIDColumns = new[] {"User"}}, //todo: check //varchar(64)?
new TableInfo("events_pollvariant", "Tenant", "Id"),
new TableInfo("events_reader", "Tenant") {UserIDColumns = new[] {"Reader"}}, //todo: check
new TableInfo("forum_answer", "TenantID", "id")
{
UserIDColumns = new[] {"user_id"},
DateColumns = new Dictionary<string, bool> {{"create_date", false}}
},
new TableInfo("forum_answer_variant"),
new TableInfo("forum_attachment", "TenantID", "id")
{
DateColumns = new Dictionary<string, bool> {{"create_date", false}}
},
new TableInfo("forum_category", "TenantID", "id")
{
UserIDColumns = new[] {"poster_id"},
DateColumns = new Dictionary<string, bool> {{"create_date", false}}
},
new TableInfo("forum_lastvisit", "tenantid")
{
UserIDColumns = new[] {"user_id"},
DateColumns = new Dictionary<string, bool> {{"last_visit", false}}
},
new TableInfo("forum_post", "TenantID", "id")
{
UserIDColumns = new[] {"poster_id", "editor_id"},
DateColumns = new Dictionary<string, bool> {{"create_date", false}, {"edit_date", false}, {"LastModified", false}}
},
new TableInfo("forum_question", "TenantID", "id") {DateColumns = new Dictionary<string, bool> {{"create_date", false}}},
new TableInfo("forum_tag", "TenantID", "id"),
new TableInfo("forum_thread", "TenantID", "id")
{
UserIDColumns = new[] {"recent_poster_id"},
DateColumns = new Dictionary<string, bool> {{"recent_post_date", false}}
},
new TableInfo("forum_topic", "TenantID", "id")
{
UserIDColumns = new[] {"poster_id"},
DateColumns = new Dictionary<string, bool> {{"create_date", false}, {"LastModified", false}}
},
new TableInfo("forum_topicwatch", "TenantID") {UserIDColumns = new[] {"UserID"}},
new TableInfo("forum_topic_tag"),
new TableInfo("forum_variant", idColumn: "id"),
new TableInfo("wiki_categories", "Tenant"),
new TableInfo("wiki_comments", "Tenant", "Id", IdType.Guid)
{
UserIDColumns = new[] {"UserId"},
DateColumns = new Dictionary<string, bool> {{"Date", false}}
},
new TableInfo("wiki_files", "Tenant")
{
UserIDColumns = new[] {"UserID"},
DateColumns = new Dictionary<string, bool> {{"Date", false}}
},
new TableInfo("wiki_pages", "tenant", "id", IdType.Autoincrement)
{
UserIDColumns = new[] {"modified_by"},
DateColumns = new Dictionary<string, bool> {{"modified_on", false}}
},
new TableInfo("wiki_pages_history", "Tenant")
{
UserIDColumns = new[] {"create_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}}
},
};
private readonly RelationInfo[] _tableRelations = new[]
{
new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_bookmarktag", "BookmarkID"),
new RelationInfo("bookmarking_tag", "TagID", "bookmarking_bookmarktag", "TagID"),
new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_comment", "BookmarkID"),
new RelationInfo("bookmarking_comment", "ID", "bookmarking_comment", "Parent"),
new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_userbookmark", "BookmarkID"),
new RelationInfo("bookmarking_tag", "TagID", "bookmarking_userbookmarktag", "TagID"),
new RelationInfo("bookmarking_userbookmark", "UserBookmarkID", "bookmarking_userbookmarktag", "UserBookmarkID"),
new RelationInfo("blogs_comments", "id", "blogs_comments", "parent_id"),
new RelationInfo("blogs_posts", "id", "blogs_comments", "post_id"),
new RelationInfo("blogs_comments", "id", "blogs_posts", "LastCommentId", null, null, RelationImportance.Low),
new RelationInfo("blogs_posts", "id", "blogs_reviewposts", "post_id"),
new RelationInfo("blogs_posts", "id", "blogs_tags", "post_id"),
new RelationInfo("events_feed", "Id", "events_comment", "Feed"),
new RelationInfo("events_comment", "Id", "events_comment", "Parent"),
new RelationInfo("events_feed", "Id", "events_poll", "Id"),
new RelationInfo("events_pollvariant", "Id", "events_pollanswer", "Variant"),
new RelationInfo("events_feed", "Id", "events_pollvariant", "Poll"),
new RelationInfo("events_feed", "Id", "events_reader", "Feed"),
new RelationInfo("forum_question", "id", "forum_answer", "question_id"),
new RelationInfo("forum_answer", "id", "forum_answer_variant", "answer_id"),
new RelationInfo("forum_variant", "id", "forum_answer_variant", "variant_id"),
new RelationInfo("forum_post", "id", "forum_attachment", "post_id"),
new RelationInfo("forum_category", "id", "forum_attachment", "path"),
new RelationInfo("forum_thread", "id", "forum_attachment", "path"),
new RelationInfo("forum_thread", "id", "forum_lastvisit", "thread_id"),
new RelationInfo("forum_topic", "id", "forum_post", "topic_id"),
new RelationInfo("forum_post", "id", "forum_post", "parent_post_id"),
new RelationInfo("forum_topic", "id", "forum_question", "topic_id"),
new RelationInfo("forum_category", "id", "forum_thread", "category_id"),
new RelationInfo("forum_post", "id", "forum_thread", "recent_post_id", null, null, RelationImportance.Low),
new RelationInfo("forum_topic", "id", "forum_thread", "recent_topic_id", null, null, RelationImportance.Low),
new RelationInfo("forum_thread", "id", "forum_topic", "thread_id"),
new RelationInfo("forum_question", "id", "forum_topic", "question_id", null, null, RelationImportance.Low),
new RelationInfo("forum_post", "id", "forum_topic", "recent_post_id", null, null, RelationImportance.Low),
new RelationInfo("forum_topic", "id", "forum_topicwatch", "TopicID"),
new RelationInfo("forum_topic", "id", "forum_topic_tag", "topic_id"),
new RelationInfo("forum_tag", "id", "forum_topic_tag", "tag_id"),
new RelationInfo("forum_question", "id", "forum_variant", "question_id"),
new RelationInfo("wiki_comments", "Id", "wiki_comments", "ParentId")
};
public CommunityModuleSpecifics(Helpers helpers)
: base(helpers) { }
public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
filePath = PreparePath(dump, columnMapper, "/", filePath);
return filePath != null;
}
protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
{
relations = relations.ToList();
if (relations.All(x => x.ChildTable == "forum_attachment" && x.ChildColumn == "path"))
{
value = PreparePath(dump, columnMapper, "\\", Convert.ToString(value));
return value != null;
}
return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
{
var column = columnName.ToLowerInvariant();
if (table.Name == "forum_post" && column == "text" ||
table.Name == "events_feed" && column == "text" ||
table.Name == "events_comment" && column == "comment" ||
table.Name == "blogs_posts" && column == "content" ||
table.Name == "blogs_comments" && column == "content" ||
table.Name == "bookmarking_comment" && column == "content" ||
table.Name == "wiki_comments" && column == "body")
{
value = FCKEditorPathUtility.CorrectStoragePath(value as string, columnMapper.GetTenantMapping());
return true;
}
return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
}
protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
if (table.Name == "forum_answer_variant")
{
return "inner join forum_answer as t1 on t1.id = t.answer_id where t1.TenantID = " + tenantId;
}
if (table.Name == "forum_variant")
{
return "inner join forum_question as t1 on t1.id = t.question_id where t1.TenantID = " + tenantId;
}
if (table.Name == "forum_topic_tag")
{
return "inner join forum_topic as t1 on t1.id = t.topic_id where t1.TenantID = " + tenantId;
}
return base.GetSelectCommandConditionText(tenantId, table);
}
private static string PreparePath(bool dump, ColumnMapper columnMapper, string partsSeparator, string path)
{
var parts = path.Split(new[] { partsSeparator }, StringSplitOptions.None);
if (parts.Length != 4)
{
return null;
}
var categoryId = columnMapper.GetMapping("forum_category", "id", parts[0]);
if (categoryId == null)
{
if (!dump)
{
return null;
}
categoryId = parts[0];
}
var threadId = columnMapper.GetMapping("forum_thread", "id", parts[1]);
if (threadId == null)
{
if (!dump)
{
return null;
}
threadId = parts[1];
}
parts[0] = categoryId.ToString();
parts[1] = threadId.ToString();
return string.Join(partsSeparator, parts);
}
}

View File

@ -91,51 +91,6 @@ public class CoreModuleSpecifics : ModuleSpecificsBase
new RelationInfo("core_group", "id", "core_usergroup", "groupid", typeof(TenantsModuleSpecifics),
x => !helpers.IsEmptyOrSystemGroup(Convert.ToString(x["groupid"]))),
new RelationInfo("crm_contact", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
x => Convert.ToString(x["object"]).StartsWith(CrmCompanyAclObjectStart) || Convert.ToString(x["object"]).StartsWith(CrmPersonAclObjectStart)),
new RelationInfo("crm_deal", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
x => Convert.ToString(x["object"]).StartsWith(CrmDealAclObjectStart)),
new RelationInfo("crm_case", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
x => Convert.ToString(x["object"]).StartsWith(CrmCasesAclObjectStart)),
new RelationInfo("crm_relationship_event", "id", "core_acl", "object", typeof(CrmModuleSpecifics2),
x => Convert.ToString(x["object"]).StartsWith(CrmRelationshipEventAclObjectStart)),
new RelationInfo("calendar_calendars", "id", "core_acl", "object", typeof(CalendarModuleSpecifics),
x => Convert.ToString(x["object"]).StartsWith(CalendarCalendarAclObjectStart)),
new RelationInfo("calendar_events", "id", "core_acl", "object", typeof(CalendarModuleSpecifics),
x => Convert.ToString(x["object"]).StartsWith(CalendarEventAclObjectStart)),
new RelationInfo("projects_projects", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
x => ValidateSource(_projectsSourceID, x)),
new RelationInfo("projects_tasks", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
x => ValidateSource(_projectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Task_")),
new RelationInfo("projects_messages", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
x => ValidateSource(_projectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Message_")),
new RelationInfo("projects_milestones", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
x => ValidateSource(_projectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Milestone_")),
new RelationInfo("bookmarking_bookmark", "ID", "core_subscription", "object", typeof(CommunityModuleSpecifics),
x => ValidateSource(_bookmarksSourceID, x) && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),
new RelationInfo("forum_topic", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
x => ValidateSource(_forumsSourceID, x) && Convert.ToString(x["action"]) == ForumsNewPostInTopicActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),
new RelationInfo("forum_thread", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
x => ValidateSource(_forumsSourceID, x) && Convert.ToString(x["action"]) == ForumsNewPostInThreadActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),
new RelationInfo("events_feed", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
x => ValidateSource(_newsSourceID, x) && Convert.ToString(x["action"]) == NewsNewCommentActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),
new RelationInfo("blogs_posts", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
x => ValidateSource(_blogsSourceID, x) && Convert.ToString(x["action"]) == BlogsNewCommentActionID),
new RelationInfo("core_user", "id", "feed_users", "user_id", typeof(CoreModuleSpecifics)),
new RelationInfo("files_folder", "id", "backup_backup", "storage_base_path", typeof(FilesModuleSpecifics),

View File

@ -1,356 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
public class CrmModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.Crm;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("crm_case", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}}
},
new TableInfo("crm_contact", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}}
},
new TableInfo("crm_contact_info", "tenant_id", "id")
{
UserIDColumns = new[] {"last_modifed_by"},
DateColumns = new Dictionary<string, bool> {{"last_modifed_on", false}}
},
new TableInfo("crm_deal", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}, {"expected_close_date", true}, {"actual_close_date", true}}
},
new TableInfo("crm_deal_milestone", "tenant_id", "id"),
new TableInfo("crm_field_description", "tenant_id", "id"),
new TableInfo("crm_list_item", "tenant_id", "id"),
new TableInfo("crm_projects", "tenant_id"),
new TableInfo("crm_tag", "tenant_id", "id"),
new TableInfo("crm_task", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}, {"deadline", true}}
},
new TableInfo("crm_task_template", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}}
},
new TableInfo("crm_task_template_container", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modifed_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modifed_on", false}}
},
new TableInfo("crm_task_template_task", "tenant_id"),
new TableInfo("crm_currency_rate", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}}
}
};
private readonly RelationInfo[] _tableRelations = new[]
{
new RelationInfo("crm_contact", "id", "crm_contact", "company_id"),
new RelationInfo("crm_list_item", "id", "crm_contact", "status_id"),
new RelationInfo("crm_list_item", "id", "crm_contact", "contact_type_id"),
new RelationInfo("crm_contact", "id", "crm_contact_info", "contact_id"),
new RelationInfo("crm_deal_milestone", "id", "crm_deal", "deal_milestone_id"),
new RelationInfo("crm_contact", "id", "crm_deal", "contact_id"),
new RelationInfo("projects_projects", "id", "crm_projects", "project_id", typeof(ProjectsModuleSpecifics)),
new RelationInfo("crm_contact", "id", "crm_projects", "contact_id"),
new RelationInfo("crm_contact", "id", "crm_task", "entity_id", x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_task", "entity_id", x => ResolveRelation(x, 1)),
new RelationInfo("crm_task", "id", "crm_task", "entity_id", x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_task", "entity_id", x => ResolveRelation(x, 7)),
new RelationInfo("crm_contact", "id", "crm_task", "contact_id"),
new RelationInfo("crm_list_item", "id", "crm_task", "category_id"),
new RelationInfo("crm_list_item", "id", "crm_task_template", "category_id"),
new RelationInfo("crm_task_template_container", "id", "crm_task_template", "container_id"),
new RelationInfo("crm_task", "id", "crm_task_template_task", "task_id"),
new RelationInfo("crm_task_template", "id", "crm_task_template_task", "task_template_id")
};
public CrmModuleSpecifics(Helpers helpers)
: base(helpers) { }
public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
var pathMatch = Regex.Match(filePath, @"^photos/\d+/\d+/\d+/contact_(?'contactId'\d+)(?'sizeExtension'_\d+_\d+\.\w+)$", RegexOptions.Compiled);
if (pathMatch.Success)
{
var contactId = columnMapper.GetMapping("crm_contact", "id", pathMatch.Groups["contactId"].Value);
if (contactId == null)
{
if (!dump)
{
return false;
}
contactId = pathMatch.Groups["contactId"].Value;
}
var s = contactId.ToString().PadLeft(6, '0');
filePath = string.Format("photos/{0}/{1}/{2}/contact_{3}{4}", s.Substring(0, 2), s.Substring(2, 2), s.Substring(4), contactId, pathMatch.Groups["sizeExtension"].Value);
return true;
}
return false;
}
private static bool ResolveRelation(DataRowInfo row, params int[] matchingTypes)
{
var entityType = Convert.ToInt32(row["entity_type"]);
return matchingTypes.Contains(entityType);
}
}
//todo: hack: in future there be no modules only tables!!!
public class CrmModuleSpecifics2 : ModuleSpecificsBase
{
public override string ConnectionStringName => "crm";
public override ModuleName ModuleName => ModuleName.Crm2;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("crm_field_value", "tenant_id", "id", IdType.Autoincrement) {UserIDColumns = new[] {"last_modifed_by"}},
new TableInfo("crm_entity_contact"),
new TableInfo("crm_entity_tag"),
new TableInfo("crm_relationship_event", "tenant_id", "id") {UserIDColumns = new[] {"create_by", "last_modifed_by"}},
};
private readonly RelationInfo[] _tableRelations = new[]
{
new RelationInfo("crm_contact", "id", "crm_field_value", "entity_id", x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_field_value", "entity_id", x => ResolveRelation(x, 1)),
new RelationInfo("crm_task", "id", "crm_field_value", "entity_id", x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_field_value", "entity_id", x => ResolveRelation(x, 7)),
new RelationInfo("crm_field_description", "id", "crm_field_value", "field_id"),
new RelationInfo("crm_contact", "id", "crm_entity_contact", "entity_id", x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_entity_contact", "entity_id", x => ResolveRelation(x, 1)),
new RelationInfo("crm_task", "id", "crm_entity_contact", "entity_id", x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_entity_contact", "entity_id", x => ResolveRelation(x, 7)),
new RelationInfo("crm_contact", "id", "crm_entity_contact", "contact_id"),
new RelationInfo("crm_contact", "id", "crm_entity_tag", "entity_id", x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_entity_tag", "entity_id", x => ResolveRelation(x, 1)),
new RelationInfo("crm_task", "id", "crm_entity_tag", "entity_id", x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_entity_tag", "entity_id", x => ResolveRelation(x, 7)),
new RelationInfo("crm_tag", "id", "crm_entity_tag", "tag_id"),
new RelationInfo("crm_contact", "id", "crm_relationship_event", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_relationship_event", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 1)),
new RelationInfo("crm_relationship_event", "id", "crm_relationship_event", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)),
new RelationInfo("crm_task", "id", "crm_relationship_event", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_relationship_event", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 7)),
new RelationInfo("crm_contact", "id", "crm_relationship_event", "contact_id", typeof(CrmModuleSpecifics)),
new RelationInfo("crm_list_item", "id", "crm_relationship_event", "category_id", typeof(CrmModuleSpecifics)),
new RelationInfo("crm_relationship_event", "id", "crm_field_value", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)),
new RelationInfo("crm_relationship_event", "id", "crm_entity_tag", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)),
new RelationInfo("crm_relationship_event", "id", "crm_entity_contact", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)),
new RelationInfo("mail_mail", "id", "crm_relationship_event", "content", typeof(MailModuleSpecifics), x => Convert.ToInt32(x["category_id"]) == -3),
};
public CrmModuleSpecifics2(Helpers helpers) : base(helpers) { }
public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
var match = Regex.Match(filePath, @"(?<=folder_\d+/message_)\d+(?=\.html)"); //todo:
if (match.Success)
{
var mappedMessageId = Convert.ToString(columnMapper.GetMapping("mail_mail", "id", match.Value));
if (dump && string.IsNullOrEmpty(mappedMessageId))
{
mappedMessageId = match.Value;
}
if (!string.IsNullOrEmpty(mappedMessageId))
{
filePath = string.Format("folder_{0}/message_{1}.html", (Convert.ToInt32(mappedMessageId) / 1000 + 1) * 1000, mappedMessageId);
}
return true;
}
return base.TryAdjustFilePath(dump, columnMapper, ref filePath);
}
protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
if (table.Name == "crm_entity_contact")
{
return "inner join crm_contact as t1 on t1.id = t.contact_id where t1.tenant_id = " + tenantId;
}
if (table.Name == "crm_entity_tag")
{
return "inner join crm_tag as t1 on t1.id = t.tag_id where t1.tenant_id = " + tenantId;
}
return base.GetSelectCommandConditionText(tenantId, table);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
{
if (relation.ChildTable == "crm_relationship_event" && relation.ChildColumn == "content")
{
value = Regex.Replace(
Convert.ToString(value),
@"(?<=""message_id"":|/Products/CRM/HttpHandlers/filehandler\.ashx\?action=mailmessage&message_id=)\d+",
match =>
{
var mappedMessageId = Convert.ToString(columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, match.Value));
var success = !string.IsNullOrEmpty(mappedMessageId);
return success ? mappedMessageId : match.Value;
});
return true;
}
return base.TryPrepareValue(connection, columnMapper, relation, ref value);
}
private static bool ResolveRelation(DataRowInfo row, params int[] matchingTypes)
{
var entityType = Convert.ToInt32(row["entity_type"]);
return matchingTypes.Contains(entityType);
}
}
public class CrmInvoiceModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.CrmInvoice;
public override string ConnectionStringName => "crm";
public override IEnumerable<TableInfo> Tables
{
get
{
return new List<TableInfo>
{
new TableInfo("crm_organisation_logo", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}}
},
new TableInfo("crm_invoice", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}, {"due_date", false}, {"issue_date", false}}
},
new TableInfo("crm_invoice_item", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}}
},
new TableInfo("crm_invoice_line", "tenant_id", "id"),
new TableInfo("crm_invoice_tax", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}}
}
};
}
}
public override IEnumerable<RelationInfo> TableRelations
{
get
{
return new List<RelationInfo>
{
new RelationInfo("crm_contact", "id", "crm_invoice", "contact_id"),
new RelationInfo("crm_contact", "id", "crm_invoice", "consignee_id"),
new RelationInfo("crm_contact", "id", "crm_invoice", "entity_id", x => ResolveRelation(x, 0, 4, 5)),
new RelationInfo("crm_deal", "id", "crm_invoice", "entity_id", x => ResolveRelation(x, 1)),
new RelationInfo("crm_task", "id", "crm_invoice", "entity_id", x => ResolveRelation(x, 3)),
new RelationInfo("crm_case", "id", "crm_invoice", "entity_id", x => ResolveRelation(x, 7)),
new RelationInfo("files_file", "id", "crm_invoice", "file_id", typeof(FilesModuleSpecifics)),
new RelationInfo("crm_invoice_tax", "id", "crm_invoice_item", "invoice_tax1_id"),
new RelationInfo("crm_invoice_tax", "id", "crm_invoice_item", "invoice_tax2_id"),
new RelationInfo("crm_invoice_tax", "id", "crm_invoice_line", "invoice_tax1_id"),
new RelationInfo("crm_invoice_tax", "id", "crm_invoice_line", "invoice_tax2_id"),
new RelationInfo("crm_invoice", "id", "crm_invoice_line", "invoice_id"),
new RelationInfo("crm_invoice_item", "id", "crm_invoice_line", "invoice_item_id"),
};
}
}
public CrmInvoiceModuleSpecifics(Helpers helpers) : base(helpers) { }
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
{
if (value == null)
{
return false;
}
if (table.Name == "crm_invoice" && columnName == "json_data")
{
var data = JObject.Parse((string)value);
var oldValue = Convert.ToInt32(data["LogoBase64Id"]);
if (oldValue != 0)
{
data["LogoBase64Id"] = Convert.ToInt32(columnMapper.GetMapping("crm_organisation_logo", "id", oldValue));
}
oldValue = Convert.ToInt32(data["DeliveryAddressID"]);
if (oldValue != 0)
{
data["DeliveryAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue));
}
oldValue = Convert.ToInt32(data["BillingAddressID"]);
if (oldValue != 0)
{
data["BillingAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue));
}
value = data.ToString();
return true;
}
return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
}
private static bool ResolveRelation(DataRowInfo row, params int[] matchingTypes)
{
var entityType = Convert.ToInt32(row["entity_type"]);
return matchingTypes.Contains(entityType);
}
}

View File

@ -74,11 +74,6 @@ public class FilesModuleSpecifics : ModuleSpecificsBase
}),
new RelationInfo("core_user", "id", "files_security", "subject", typeof(TenantsModuleSpecifics)),
new RelationInfo("core_group", "id", "files_security", "subject", typeof(TenantsModuleSpecifics)),
new RelationInfo("crm_deal", "id", "files_bunch_objects", "right_node", typeof(CrmModuleSpecifics),
x => Convert.ToString(x["right_node"]).StartsWith(_bunchRightNodeStartCrmOpportunity)),
new RelationInfo("projects_projects", "id", "files_bunch_objects", "right_node", typeof(ProjectsModuleSpecifics),
x => Convert.ToString(x["right_node"]).StartsWith(_bunchRightNodeStartProject, StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("files_folder", "id", "files_bunch_objects", "left_node"),
new RelationInfo("files_folder", "id", "files_file", "folder_id"),
@ -318,18 +313,6 @@ public class FilesModuleSpecifics2 : ModuleSpecificsBase
private readonly RelationInfo[] _rels = new[]
{
new RelationInfo("projects_messages", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
x => Convert.ToString(x["name"]).StartsWith(_tagStartMessage, StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("projects_tasks", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
x => Convert.ToString(x["name"]).StartsWith(_tagStartTask, StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("projects_projects", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
x => Convert.ToString(x["name"]).StartsWith(_tagStartProject, StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("crm_relationship_event", "id", "files_tag", "name", typeof(CrmModuleSpecifics2),
x => Convert.ToString(x["name"]).StartsWith(_tagStartRelationshipEvent, StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("files_tag", "id", "files_tag_link", "tag_id", typeof(FilesModuleSpecifics)),
new RelationInfo("files_file", "id", "files_tag_link", "entry_id", typeof(FilesModuleSpecifics),

View File

@ -29,16 +29,9 @@ namespace ASC.Data.Backup.Tasks.Modules;
public enum ModuleName
{
Audit,
Calendar,
Community,
Core,
Crm,
Crm2,
CrmInvoice,
Files,
Files2,
Mail,
Projects,
Tenants,
WebStudio
}

View File

@ -1,304 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
internal class MailModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.Mail;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly ILogger<ModuleProvider> _logger;
private readonly Helpers _helpers;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("mail_attachment", "tenant", "id"),
new TableInfo("mail_chain", "tenant") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_contacts", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_folder_counters", "tenant") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_mail", "tenant", "id")
{
UserIDColumns = new[] {"id_user"},
DateColumns = new Dictionary<string, bool> {{"date_received", false}, {"date_sent", false}, {"chain_date", false}}
},
new TableInfo("mail_mailbox", "tenant", "id")
{
UserIDColumns = new[] {"id_user"},
DateColumns = new Dictionary<string, bool> {{"begin_date", false}}
},
new TableInfo("mail_tag", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_tag_addresses", "tenant"),
new TableInfo("mail_tag_mail", "tenant") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_chain_x_crm_entity", "id_tenant"),
new TableInfo("mail_mailbox_signature", "tenant"),
new TableInfo("mail_mailbox_autoreply", "tenant"),
new TableInfo("mail_mailbox_autoreply_history", "tenant"),
new TableInfo("mail_contact_info", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
new TableInfo("mail_mailbox_provider", idColumn: "id"),
new TableInfo("mail_mailbox_domain", idColumn: "id"),
new TableInfo("mail_mailbox_server", idColumn: "id")
};
private readonly RelationInfo[] _tableRelations = new[]
{
new RelationInfo("mail_mail", "id", "mail_attachment", "id_mail"),
new RelationInfo("mail_mailbox", "id", "mail_chain", "id_mailbox"),
new RelationInfo("mail_tag", "id", "mail_chain", "tags"),
new RelationInfo("crm_tag", "id", "mail_chain", "tags", typeof(CrmModuleSpecifics)),
new RelationInfo("mail_mailbox", "id", "mail_mail", "id_mailbox"),
new RelationInfo("crm_tag", "id", "mail_tag", "crm_id", typeof(CrmModuleSpecifics)),
new RelationInfo("mail_tag", "id", "mail_tag_addresses", "id_tag", x => Convert.ToInt32(x["id_tag"]) > 0),
new RelationInfo("crm_tag", "id", "mail_tag_addresses", "id_tag", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["id_tag"]) < 0),
new RelationInfo("mail_mail", "id", "mail_tag_mail", "id_mail"),
new RelationInfo("mail_tag", "id", "mail_tag_mail", "id_tag", x => Convert.ToInt32(x["id_tag"]) > 0),
new RelationInfo("crm_tag", "id", "mail_tag_mail", "id_tag", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["id_tag"]) < 0),
new RelationInfo("mail_mailbox", "id", "mail_chain_x_crm_entity", "id_mailbox"),
new RelationInfo("crm_contact", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 1),
new RelationInfo("crm_case", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 2),
new RelationInfo("crm_deal", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 3),
new RelationInfo("mail_mailbox", "id", "mail_mailbox_signature", "id_mailbox"),
new RelationInfo("files_folder", "id", "mail_mailbox", "email_in_folder", typeof(FilesModuleSpecifics)),
new RelationInfo("mail_mailbox", "id", "mail_mailbox_autoreply", "id_mailbox"),
new RelationInfo("mail_mailbox", "id", "mail_mailbox_autoreply_history", "id_mailbox"),
new RelationInfo("mail_contacts", "id", "mail_contact_info", "id_contact"),
new RelationInfo("mail_mailbox_provider", "id", "mail_mailbox_domain", "id_provider"),
new RelationInfo("mail_mailbox_server", "id", "mail_mailbox", "id_smtp_server"),
new RelationInfo("mail_mailbox_server", "id", "mail_mailbox", "id_in_server")
};
public MailModuleSpecifics(ILogger<ModuleProvider> logger, Helpers helpers) : base(helpers)
{
_logger = logger;
_helpers = helpers;
}
public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
//todo: hack: will be changed later
filePath = Regex.Replace(filePath, @"^[-\w]+(?=/)", match => dump ? match.Value : columnMapper.GetUserMapping(match.Value));
return !filePath.StartsWith("/");
}
public override void PrepareData(DataTable data)
{
if (data.TableName == "mail_mailbox")
{
var address = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "address");
var smtp = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "smtp_password");
var pop3 = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "pop3_password");
var token = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "token");
for (var i = 0; i < data.Rows.Count; i++)
{
var row = data.Rows[i];
try
{
row[smtp] = _helpers.CreateHash2(row[smtp] as string);
row[pop3] = _helpers.CreateHash2(row[pop3] as string);
row[token] = _helpers.CreateHash2(row[token] as string);
}
catch (Exception ex)
{
_logger.ErrorCanNotPrepareData(row[address] as string, ex);
data.Rows.Remove(row);
i--;
}
}
}
}
public override Stream PrepareData(string key, Stream stream, ColumnMapper columnMapper)
{
if (!key.EndsWith("body.html"))
{
return stream;
}
using (var streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
{
var data = streamReader.ReadToEnd();
data = Regex.Replace(data, @"(htmleditorfiles|aggregator)(\/0\/|\/[\d]+\/\d\d\/\d\d\/)([-\w]+(?=/))",
match => "/" + TenantPath.CreatePath(columnMapper.GetTenantMapping().ToString()) + "/" + columnMapper.GetUserMapping(match.Groups[3].Value));
var content = Encoding.UTF8.GetBytes(data);
stream.Position = 0;
stream.Write(content, 0, content.Length);
}
return stream;
}
protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
//optimization: 1) do not include "deleted" rows, 2) backup mail only for the last 30 days
switch (table.Name)
{
case "mail_mailbox_provider":
return string.Format("where t.id in " +
"(select distinct t2.id_provider from mail_mailbox t1 " +
"inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
"where t1.tenant = {0} and t1.is_removed = 0)", tenantId);
// mail_mailbox_domain.id_provider not in index
case "mail_mailbox_domain":
return string.Format("where t.id_provider in " +
"(select distinct t2.id_provider from mail_mailbox t1 " +
"inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
"where t1.tenant = {0} and t1.is_removed = 0)", tenantId);
case "mail_mailbox_server":
return string.Format("where t.id in " +
"(select distinct t2.id from mail_mailbox t1 " +
"inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
"where t1.tenant = {0} and t1.is_removed = 0)", tenantId);
case "mail_mailbox":
return string.Format("where t.is_removed = 0 and t.tenant = {0}", tenantId);
//condition on chain_date because of Bug 18855 - transfer mail only for the last 30 days
case "mail_mail":
return string.Format("inner join mail_mailbox t1 on t1.id = t.id_mailbox " +
"where t.tenant = {0} and t1.tenant = {0} and t.is_removed = 0 and t1.is_removed = 0 and t.chain_date > '{1}'",
tenantId,
DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)).ToString("yyyy-MM-dd HH:mm:ss"));
case "mail_attachment":
case "mail_tag_mail":
return string.Format("inner join mail_mail as t1 on t1.id = t.id_mail " +
"inner join mail_mailbox as t2 on t2.id = t1.id_mailbox " +
"where t1.tenant = {0} and t2.tenant = {0} and t1.is_removed = 0 and t2.is_removed = 0 and t1.chain_date > '{1}'",
tenantId,
DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)).ToString("yyyy-MM-dd HH:mm:ss"));
case "mail_chain":
return string.Format("inner join mail_mailbox t1 on t1.id = t.id_mailbox " +
"where t.tenant = {0} and t1.is_removed = 0",
tenantId);
default:
return base.GetSelectCommandConditionText(tenantId, table);
}
}
protected override string GetDeleteCommandConditionText(int tenantId, TableInfo table)
{
//delete all rows regardless of whether there is is_removed = 1 or not
return base.GetSelectCommandConditionText(tenantId, table);
}
protected override bool TryPrepareRow(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row, out Dictionary<string, object> preparedRow)
{
if (table.Name == "mail_mailbox")
{
var boxType = row["is_server_mailbox"];
if (boxType != null && Convert.ToBoolean(int.Parse(boxType.ToString())))
{
preparedRow = null;
return false;
}
}
return base.TryPrepareRow(dump, connection, columnMapper, table, row, out preparedRow);
}
protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
{
relations = relations.ToList();
if (relations.All(x => x.ChildTable == "mail_chain" && x.ChildColumn == "tags"))
{
var mappedTags = new List<string>();
foreach (var tag in value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x)))
{
object tagId;
if (tag > 0)
{
tagId = columnMapper.GetMapping("mail_tag", "id", tag);
}
else
{
tagId = columnMapper.GetMapping("crm_tag", "id", -tag);
if (tagId != null)
{
tagId = -Convert.ToInt32(tagId);
}
}
if (tagId != null)
{
mappedTags.Add(tagId.ToString());
}
}
value = string.Join(",", mappedTags.ToArray());
return true;
}
return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
{
if (relation.ParentTable == "crm_tag" && relation.ChildColumn == "id_tag"
&& (relation.ChildTable == "mail_tag_mail" || relation.ChildTable == "mail_tag_addresses"))
{
var crmTagId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, -Convert.ToInt32(value));
if (crmTagId == null)
{
return false;
}
value = -Convert.ToInt32(crmTagId);
return true;
}
return base.TryPrepareValue(connection, columnMapper, relation, ref value);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
{
if (table.Name == "mail_mailbox" && (columnName == "smtp_password" || columnName == "pop3_password") && value != null)
{
try
{
value = _helpers.CreateHash(value as string); // save original hash
}
catch (Exception err)
{
_logger.ErrorCanNotPrepareValue(value, err);
value = null;
}
return true;
}
return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
}
}

View File

@ -37,15 +37,8 @@ public class ModuleProvider
{
new TenantsModuleSpecifics(coreSettings,helpers),
new AuditModuleSpecifics(helpers),
new CommunityModuleSpecifics(helpers),
new CalendarModuleSpecifics(helpers),
new ProjectsModuleSpecifics(helpers),
new CrmModuleSpecifics(helpers),
new FilesModuleSpecifics(logger,helpers),
new MailModuleSpecifics(logger,helpers),
new CrmModuleSpecifics2(helpers),
new FilesModuleSpecifics2(helpers),
new CrmInvoiceModuleSpecifics(helpers),
new WebStudioModuleSpecifics(helpers),
new CoreModuleSpecifics(helpers)
}
@ -56,10 +49,6 @@ public class ModuleProvider
return storageModuleName switch
{
"files" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Files),
"projects" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Projects),
"crm" => AllModules.FirstOrDefault(m => m.ModuleName == (storageDomainName == "mail_messages" ? ModuleName.Crm2 : ModuleName.Crm)),
"forum" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Community),
"mailaggregator" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Mail),
_ => null,
};
}

View File

@ -1,204 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
public class ProjectsModuleSpecifics : ModuleSpecificsBase
{
public override ModuleName ModuleName => ModuleName.Projects;
public override IEnumerable<TableInfo> Tables => _tables;
public override IEnumerable<RelationInfo> TableRelations => _tableRelations;
private readonly TableInfo[] _tables = new[]
{
new TableInfo("projects_comments", "tenant_id", "comment_id", IdType.Autoincrement) {UserIDColumns = new[] {"create_by"}},
new TableInfo("projects_following_project_participant") {UserIDColumns = new[] {"participant_id"}},
new TableInfo("projects_messages", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by"},
DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}}
},
new TableInfo("projects_milestones", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"deadline", true}, {"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
},
new TableInfo("projects_projects", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
},
new TableInfo("projects_project_participant", "tenant") {UserIDColumns = new[] {"participant_id"}},
new TableInfo("projects_project_tag"),
new TableInfo("projects_report_template", "tenant_id", "id") {UserIDColumns = new[] {"create_by"}},
new TableInfo("projects_subtasks", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
},
new TableInfo("projects_tags", "tenant_id", "id"),
new TableInfo("projects_tasks", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
DateColumns = new Dictionary<string, bool> {{"status_changed", true}, {"deadline", true}, {"create_on", false}, {"last_modified_on", true}, {"start_date", true}}
},
new TableInfo("projects_tasks_responsible", "tenant_id") {UserIDColumns = new[] {"responsible_id"}},
new TableInfo("projects_templates", "tenant_id", "id") {UserIDColumns = new[] {"create_by", "last_modified_by"}},
new TableInfo("projects_time_tracking", "tenant_id", "id")
{
UserIDColumns = new[] {"create_by", "person_id"},
DateColumns = new Dictionary<string, bool> {{"date", true}, {"create_on", false}, {"status_changed", true}}
},
new TableInfo("projects_tasks_links", "tenant_id"),
new TableInfo("projects_tasks_order", "tenant_id")
};
private readonly RelationInfo[] _tableRelations = new[]
{
new RelationInfo("projects_comments", "id", "projects_comments", "parent_id"),
new RelationInfo("projects_messages", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Message_", StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("projects_tasks", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Task_", StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("projects_milestones", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Milestone_", StringComparison.InvariantCultureIgnoreCase)),
new RelationInfo("projects_projects", "id", "projects_following_project_participant", "project_id"),
new RelationInfo("projects_projects", "id", "projects_messages", "project_id"),
new RelationInfo("projects_projects", "id", "projects_milestones", "project_id"),
new RelationInfo("projects_projects", "id", "projects_project_participant", "project_id"),
new RelationInfo("projects_projects", "id", "projects_project_tag", "project_id"),
new RelationInfo("projects_tags", "id", "projects_project_tag", "tag_id"),
new RelationInfo("projects_tasks", "id", "projects_subtasks", "task_id"),
new RelationInfo("projects_projects", "id", "projects_tasks", "project_id"),
new RelationInfo("projects_milestones", "id", "projects_tasks", "milestone_id"),
new RelationInfo("projects_tasks", "id", "projects_tasks_responsible", "task_id"),
new RelationInfo("projects_projects", "id", "projects_time_tracking", "project_id"),
new RelationInfo("projects_tasks", "id", "projects_time_tracking", "relative_task_id"),
new RelationInfo("projects_tasks", "id", "projects_tasks_links", "task_id"),
new RelationInfo("projects_tasks", "id", "projects_tasks_links", "parent_id"),
new RelationInfo("projects_projects", "id", "projects_tasks_order", "project_id"),
new RelationInfo("projects_tasks", "id", "projects_tasks_order", "task_order"),
new RelationInfo("projects_milestones", "id", "projects_tasks_order", "task_order")
};
public ProjectsModuleSpecifics(Helpers helpers) : base(helpers) { }
public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
var match = Regex.Match(filePath, @"^thumbs/\d+/\d+/\d+/(?'fileId'\d+)\.jpg$");
if (match.Success)
{
var fileId = columnMapper.GetMapping("files_file", "id", match.Groups["fileId"].Value);
if (fileId == null)
{
if (!dump)
{
return false;
}
fileId = match.Groups["fileId"].Value;
}
var s = fileId.ToString().PadRight(6, '0');
filePath = string.Format("thumbs/{0}/{1}/{2}/{3}.jpg", s.Substring(0, 2), s.Substring(2, 2), s.Substring(4), fileId);
return true;
}
return false;
}
protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
if (table.Name == "projects_project_tag" || table.Name == "projects_following_project_participant")
{
return "inner join projects_projects as t1 on t1.id = t.project_id where t1.tenant_id = " + tenantId;
}
return base.GetSelectCommandConditionText(tenantId, table);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
{
if (table.Name == "projects_comments" && columnName == "content" ||
table.Name == "projects_messages" && columnName == "content")
{
value = FCKEditorPathUtility.CorrectStoragePath(value as string, columnMapper.GetTenantMapping());
return true;
}
return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
}
protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
{
if (relation.ChildTable == "projects_comments" && relation.ChildColumn == "target_uniq_id")
{
var valParts = value.ToString().Split('_');
var entityId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, valParts[1]);
if (entityId == null)
{
return false;
}
value = string.Format("{0}_{1}", valParts[0], entityId);
return true;
}
return base.TryPrepareValue(connection, columnMapper, relation, ref value);
}
protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
{
if (table.Name == "projects_tasks_order" && columnName == "task_order")
{
value = Regex.Replace(
Convert.ToString(value),
@"(?<=""tasks"":\[(\d+,)*)\d+,?",
match =>
{
var mappedId = Convert.ToString(columnMapper.GetMapping("projects_tasks", "id", match.Value.TrimEnd(',')));
return !string.IsNullOrEmpty(mappedId) && match.Value.EndsWith(',') ? mappedId + "," : mappedId;
},
RegexOptions.Compiled);
value = Regex.Replace(
Convert.ToString(value),
@"(?<=""milestones"":\[(\d+,)*)\d+,?",
match =>
{
var mappedId = Convert.ToString(columnMapper.GetMapping("projects_milestones", "id", match.Value.TrimEnd(',')));
return !string.IsNullOrEmpty(mappedId) && match.Value.EndsWith(',') ? mappedId + "," : mappedId;
},
RegexOptions.Compiled);
return true;
}
return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
}
}

View File

@ -41,11 +41,7 @@ public class WebStudioModuleSpecifics : ModuleSpecificsBase
new TableInfo("webstudio_uservisit", "tenantid") {InsertMethod = InsertMethod.None}
};
private readonly RelationInfo[] _relations = new[]
{
new RelationInfo("crm_organisation_logo", "id", "webstudio_settings", "Data", typeof(CrmInvoiceModuleSpecifics),
x => _crmSettingsId == new Guid(Convert.ToString(x["ID"])))
};
private readonly RelationInfo[] _relations = new RelationInfo[0];
public WebStudioModuleSpecifics(Helpers helpers) : base(helpers) { }

View File

@ -24,25 +24,32 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using ASC.EventBus.Log;
namespace ASC.Notify.IntegrationEvents.EventHandling;
[Scope]
public class EncryptionDataStorageRequestedIntegrationEventHandler : IIntegrationEventHandler<EncryptionDataStorageRequestedIntegration>
{
private readonly ILogger _logger;
private readonly EncryptionWorker _encryptionWorker;
public EncryptionDataStorageRequestedIntegrationEventHandler(EncryptionWorker encryptionWorker)
public EncryptionDataStorageRequestedIntegrationEventHandler(EncryptionWorker encryptionWorker,
ILogger<EncryptionDataStorageRequestedIntegrationEventHandler> logger)
{
_encryptionWorker = encryptionWorker;
_logger = logger;
}
public async Task Handle(EncryptionDataStorageRequestedIntegration @event)
{
// using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
// {
// _logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
// _logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
_encryptionWorker.Start(@event.EncryptionSettings, @event.ServerRootPath);
_encryptionWorker.Start(@event.EncryptionSettings, @event.ServerRootPath);
await Task.CompletedTask;
await Task.CompletedTask;
// }
}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog;
var options = new WebApplicationOptions
{
Args = args,
@ -32,24 +34,57 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
try
{
startup.ConfigureContainer(containerBuilder);
});
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
var app = builder.Build();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.Configure(app, app.Environment);
startup.ConfigureServices(builder.Services);
await app.RunWithTasksAsync();
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
startup.ConfigureContainer(containerBuilder);
});
var app = builder.Build();
startup.Configure(app, app.Environment);
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -24,6 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Migration.Core;
public class Startup : BaseStartup
{

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog;
var options = new WebApplicationOptions
{
Args = args,
@ -32,19 +34,52 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.Services.AddClearEventsServices();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger("ASC.ClearEvents");
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
try
{
builder.Register(context.Configuration, false, false);
});
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
builder.Services.AddClearEventsServices();
var app = builder.Build();
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
{
builder.Register(context.Configuration, false, false);
});
var app = builder.Build();
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = "ASC.ClearEvents";
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}
await app.RunWithTasksAsync();

View File

@ -32,9 +32,9 @@ public static class ConfigurationManagerExtension
this ConfigurationManager config,
IHostEnvironment env)
{
config.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true)
.AddJsonFile("backup.json");
config.AddJsonFile("notify.json", optional: false, reloadOnChange: true)
.AddJsonFile($"notify.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile("backup.json", optional: false, reloadOnChange: true);
return config;
}

View File

@ -62,5 +62,5 @@ global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using Microsoft.Extensions.Logging;
global using Newtonsoft.Json;
global using ASC.Data.Backup.Extension;

View File

@ -41,11 +41,14 @@ public class BackupDeleteScheldureRequestedIntegrationEventHandler : IIntegratio
}
public async Task Handle(IntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
_backupService.DeleteSchedule(@event.TenantId);
await Task.CompletedTask;
{
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
_backupService.DeleteSchedule(@event.TenantId);
await Task.CompletedTask;
}
}
}

View File

@ -54,36 +54,38 @@ public class BackupRequestedIntegrationEventHandler : IIntegrationEventHandler<B
public async Task Handle(BackupRequestIntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
if (!@event.Redelivered)
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
if (_backupWorker.IsInstanceTooBusy())
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
if (!@event.Redelivered)
{
throw new IntegrationEventRejectExeption(@event.Id);
if (_backupWorker.IsInstanceTooBusy())
{
throw new IntegrationEventRejectExeption(@event.Id);
}
}
}
_tenantManager.SetCurrentTenant(@event.TenantId);
_securityContext.AuthenticateMeWithoutCookie(_authManager.GetAccountByID(@event.TenantId, @event.CreateBy));
_tenantManager.SetCurrentTenant(@event.TenantId);
_securityContext.AuthenticateMeWithoutCookie(_authManager.GetAccountByID(@event.TenantId, @event.CreateBy));
if (@event.IsScheduled)
{
_backupWorker.StartScheduledBackup(new EF.Model.BackupSchedule
if (@event.IsScheduled)
{
BackupMail = @event.BackupMail,
BackupsStored = @event.BackupsStored,
StorageBasePath = @event.StorageBasePath,
StorageParams = JsonConvert.SerializeObject(@event.StorageParams),
StorageType = @event.StorageType,
TenantId = @event.TenantId
});
}
else
{
_backupAjaxHandler.StartBackup(@event.StorageType, @event.StorageParams, @event.BackupMail);
}
_backupWorker.StartScheduledBackup(new EF.Model.BackupSchedule
{
BackupsStored = @event.BackupsStored,
StorageBasePath = @event.StorageBasePath,
StorageParams = JsonConvert.SerializeObject(@event.StorageParams),
StorageType = @event.StorageType,
TenantId = @event.TenantId
});
}
else
{
_backupAjaxHandler.StartBackup(@event.StorageType, @event.StorageParams);
}
await Task.CompletedTask;
await Task.CompletedTask;
}
}
}

View File

@ -54,24 +54,27 @@ public class BackupRestoreRequestedIntegrationEventHandler : IIntegrationEventHa
public async Task Handle(BackupRestoreRequestIntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
if (!@event.Redelivered)
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
if (_backupWorker.IsInstanceTooBusy())
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
if (!@event.Redelivered)
{
throw new IntegrationEventRejectExeption(@event.Id);
if (_backupWorker.IsInstanceTooBusy())
{
throw new IntegrationEventRejectExeption(@event.Id);
}
}
_tenantManager.SetCurrentTenant(@event.TenantId);
_securityContext.AuthenticateMeWithoutCookie(_authManager.GetAccountByID(@event.TenantId, @event.CreateBy));
_backupAjaxHandler.StartRestore(@event.BackupId,
@event.StorageType,
@event.StorageParams,
@event.Notify);
await Task.CompletedTask;
}
_tenantManager.SetCurrentTenant(@event.TenantId);
_securityContext.AuthenticateMeWithoutCookie(_authManager.GetAccountByID(@event.TenantId, @event.CreateBy));
_backupAjaxHandler.StartRestore(@event.BackupId,
@event.StorageType,
@event.StorageParams,
@event.Notify);
await Task.CompletedTask;
}
}

View File

@ -46,8 +46,8 @@ internal static partial class BackupSchedulerServiceLogger
[LoggerMessage(Level = LogLevel.Debug, Message = "{count} backups are to schedule")]
public static partial void DebugBackupsSchedule(this ILogger<BackupSchedulerService> logger, int count);
[LoggerMessage(Level = LogLevel.Debug, Message = "Start scheduled backup: {tenantId}, {backupMail}, {storageType}, {storageBasePath}")]
public static partial void DebugStartScheduledBackup(this ILogger<BackupSchedulerService> logger, int tenantId, bool backupMail, BackupStorageType storageType, string storageBasePath);
[LoggerMessage(Level = LogLevel.Debug, Message = "Start scheduled backup: {tenantId}, {storageType}, {storageBasePath}")]
public static partial void DebugStartScheduledBackup(this ILogger<BackupSchedulerService> logger, int tenantId, BackupStorageType storageType, string storageBasePath);
[LoggerMessage(Level = LogLevel.Debug, Message = "Skip portal {tenantId} not paid")]
public static partial void DebugNotPaid(this ILogger<BackupSchedulerService> logger, int tenantId);

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using ASC.Data.Backup.Extension;
using NLog;
var options = new WebApplicationOptions
{
@ -34,39 +34,65 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddBackupBackgroundTasksConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
startup.ConfigureContainer(containerBuilder);
});
var app = builder.Build();
startup.Configure(app, app.Environment);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<BackupRequestIntegrationEvent, BackupRequestedIntegrationEventHandler>();
eventBus.Subscribe<BackupRestoreRequestIntegrationEvent, BackupRestoreRequestedIntegrationEventHandler>();
eventBus.Subscribe<IntegrationEvent, BackupDeleteScheldureRequestedIntegrationEventHandler>();
await app.RunWithTasksAsync();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
try
{
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
startup.ConfigureContainer(containerBuilder);
});
var app = builder.Build();
startup.Configure(app, app.Environment);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<BackupRequestIntegrationEvent, BackupRequestedIntegrationEventHandler>();
eventBus.Subscribe<BackupRestoreRequestIntegrationEvent, BackupRestoreRequestedIntegrationEventHandler>();
eventBus.Subscribe<IntegrationEvent, BackupDeleteScheldureRequestedIntegrationEventHandler>();
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1).Replace(".","");
}

View File

@ -5,7 +5,7 @@
"launchBrowser": false,
"environmentVariables": {
"$STORAGE_ROOT": "../../../Data",
"log__name": "backup",
"log__name": "backup.backgoundtasks",
"log__dir": "../../../Logs",
"core__products__folder": "../../../products",
"ASPNETCORE_ENVIRONMENT": "Development",
@ -17,7 +17,7 @@
"launchBrowser": false,
"environmentVariables": {
"$STORAGE_ROOT": "../../../Data",
"log__name": "backup",
"log__name": "backup.backgoundtasks",
"log__dir": "../../../Logs",
"core__products__folder": "../../../products",
"ASPNETCORE_ENVIRONMENT": "Development",

View File

@ -115,14 +115,13 @@ public sealed class BackupSchedulerService : BackgroundService
backupRepository.SaveBackupSchedule(schedule);
_logger.DebugStartScheduledBackup(schedule.TenantId, schedule.BackupMail, schedule.StorageType, schedule.StorageBasePath);
_logger.DebugStartScheduledBackup(schedule.TenantId, schedule.StorageType, schedule.StorageBasePath);
_eventBus.Publish(new BackupRequestIntegrationEvent(
tenantId: schedule.TenantId,
storageBasePath: schedule.StorageBasePath,
storageParams: JsonConvert.DeserializeObject<Dictionary<string, string>>(schedule.StorageParams),
storageType: schedule.StorageType,
backupMail: schedule.BackupMail,
createBy: ASC.Core.Configuration.Constants.CoreSystem.ID,
isScheduled: true,
backupsStored: schedule.BackupsStored

View File

@ -76,7 +76,6 @@ public class BackupController : ControllerBase
/// <param name="storageParams">Storage parameters</param>
/// <param name="backupsStored">Max of the backup's stored copies</param>
/// <param name="cronParams">Cron parameters</param>
/// <param name="backupMail">Include mail in the backup</param>
/// <category>Backup</category>
[HttpPost("createbackupschedule")]
public bool CreateBackupSchedule(BackupScheduleDto backupSchedule)
@ -94,7 +93,7 @@ public class BackupController : ControllerBase
Hour = backupSchedule.CronParams.Hour == null ? 0 : Int32.Parse(backupSchedule.CronParams.Hour),
Day = backupSchedule.CronParams.Day == null ? 0 : Int32.Parse(backupSchedule.CronParams.Day),
};
_backupHandler.CreateSchedule(storageType, storageParams, backupStored, cron, backupSchedule.BackupMail);
_backupHandler.CreateSchedule(storageType, storageParams, backupStored, cron);
return true;
}
@ -120,7 +119,6 @@ public class BackupController : ControllerBase
/// </summary>
/// <param name="storageType">Storage Type</param>
/// <param name="storageParams">Storage Params</param>
/// <param name="backupMail">Include mail in the backup</param>
/// <category>Backup</category>
/// <returns>Backup Progress</returns>
[HttpPost("startbackup")]
@ -137,7 +135,6 @@ public class BackupController : ControllerBase
tenantId: _tenantId,
storageParams: storageParams,
storageType: storageType,
backupMail: backup.BackupMail,
createBy: _currentUserId
));

View File

@ -29,6 +29,5 @@ namespace ASC.Data.Backup.ApiModels;
public class BackupDto
{
public string StorageType { get; set; }
public bool BackupMail { get; set; }
public IEnumerable<ItemKeyValuePair<object, object>> StorageParams { get; set; }
}

View File

@ -32,7 +32,6 @@ public class BackupScheduleDto
public IEnumerable<ItemKeyValuePair<object, object>> StorageParams { get; set; }
public string BackupsStored { get; set; }
public Cron CronParams { get; set; }
public bool BackupMail { get; set; }
}
public class Cron

View File

@ -32,8 +32,8 @@ public static class ConfigurationManagerExtension
this ConfigurationManager config,
IHostEnvironment env)
{
config.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
config.AddJsonFile("notify.json", optional: false, reloadOnChange: true)
.AddJsonFile($"notify.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return config;
}

View File

@ -58,3 +58,9 @@ global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using static ASC.Data.Backup.BackupAjaxHandler;
global using ASC.Data.Backup.Extension;
global using NLog.Extensions.Logging;
global using NLog.Web;
global using NLog.AWS.Logger;

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using ASC.Data.Backup.Extension;
using NLog;
var options = new WebApplicationOptions
{
@ -34,26 +34,59 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddBackupConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
try
{
startup.ConfigureContainer(containerBuilder);
});
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
var app = builder.Build();
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
startup.Configure(app, app.Environment);
var startup = new Startup(builder.Configuration, builder.Environment);
await app.RunWithTasksAsync();
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
startup.ConfigureContainer(containerBuilder);
});
var app = builder.Build();
startup.Configure(app, app.Environment);
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -55,7 +55,7 @@ public class Startup : BaseStartup
app.MapWhen(
context => context.Request.Path.ToString().EndsWith("backupFileUpload.ashx"),
appBranch =>
{
{
appBranch.UseBackupFileUploadHandler();
});
}

View File

@ -32,9 +32,9 @@ public static class ConfigurationManagerExtension
this ConfigurationManager config,
IHostEnvironment env)
{
config.AddJsonFile($"appsettings.services.json", true)
.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
config.AddJsonFile($"appsettings.services.json", optional: false, reloadOnChange: true)
.AddJsonFile("notify.json", optional: false, reloadOnChange: true)
.AddJsonFile($"notify.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return config;

View File

@ -74,11 +74,14 @@ public class NotifyInvokeSendMethodRequestedIntegrationEventHandler : IIntegrati
public async Task Handle(NotifyInvokeSendMethodRequestedIntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
InvokeSendMethod(@event.NotifyInvoke);
await Task.CompletedTask;
{
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
InvokeSendMethod(@event.NotifyInvoke);
await Task.CompletedTask;
}
}
}

View File

@ -54,10 +54,13 @@ public class NotifySendMessageRequestedIntegrationEventHandler : IIntegrationEve
public async Task Handle(NotifySendMessageRequestedIntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
SendNotifyMessage(@event.NotifyMessage);
SendNotifyMessage(@event.NotifyMessage);
await Task.CompletedTask;
await Task.CompletedTask;
}
}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog;
var options = new WebApplicationOptions
{
Args = args,
@ -32,33 +34,63 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddNotifyConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
var startup = new Startup(builder.Configuration, builder.Environment);
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
try
{
builder.Register(context.Configuration);
});
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
var app = builder.Build();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.Configure(app);
startup.ConfigureServices(builder.Services);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
{
builder.Register(context.Configuration);
});
eventBus.Subscribe<NotifyInvokeSendMethodRequestedIntegrationEvent, NotifyInvokeSendMethodRequestedIntegrationEventHandler>();
eventBus.Subscribe<NotifySendMessageRequestedIntegrationEvent, NotifySendMessageRequestedIntegrationEventHandler>();
var app = builder.Build();
await app.RunWithTasksAsync();
startup.Configure(app);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<NotifyInvokeSendMethodRequestedIntegrationEvent, NotifyInvokeSendMethodRequestedIntegrationEventHandler>();
eventBus.Subscribe<NotifySendMessageRequestedIntegrationEvent, NotifySendMessageRequestedIntegrationEventHandler>();
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string AppName = Assembly.GetExecutingAssembly().GetName().Name;
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -32,9 +32,9 @@ public static class ConfigurationManagerExtension
this ConfigurationManager config,
IHostEnvironment env)
{
config.AddJsonFile($"appsettings.services.json", true)
.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
config.AddJsonFile($"appsettings.services.json", optional: false, reloadOnChange: true)
.AddJsonFile("notify.json", optional: false, reloadOnChange: true)
.AddJsonFile($"notify.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return config;

View File

@ -25,6 +25,9 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using ASC.Notify.Extension;
using ASC.Studio.Notify;
using NLog;
var options = new WebApplicationOptions
{
@ -34,25 +37,58 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddStudioNotifyConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
try
{
builder.Register(context.Configuration);
});
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
var app = builder.Build();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.Configure(app);
startup.ConfigureServices(builder.Services);
await app.RunWithTasksAsync();
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
{
builder.Register(context.Configuration);
});
var app = builder.Build();
startup.Configure(app);
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1).Replace(".", "");
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Studio.Notify;
public class Startup : BaseWorkerStartup
{
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment)

View File

@ -32,8 +32,8 @@ public static class ConfigurationManagerExtension
this ConfigurationManager config,
IHostEnvironment env)
{
config.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
config.AddJsonFile("notify.json", optional: false, reloadOnChange: true)
.AddJsonFile($"notify.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return config;
}

View File

@ -48,8 +48,11 @@ public class TelegramSendMessageRequestedIntegrationEventHandler : IIntegrationE
public async Task Handle(NotifySendTelegramMessageRequestedIntegrationEvent @event)
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
using (_logger.BeginScope(new[] { new KeyValuePair<string, object>("integrationEventContext", $"{@event.Id}-{Program.AppName}") }))
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
await _telegramHandler.SendMessage(@event.NotifyMessage);
await _telegramHandler.SendMessage(@event.NotifyMessage);
}
}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog;
var options = new WebApplicationOptions
{
Args = args,
@ -32,34 +34,60 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddTelegramConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
try
{
startup.ConfigureContainer(containerBuilder);
});
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
var app = builder.Build();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.Configure(app, app.Environment);
startup.ConfigureServices(builder.Services);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
startup.ConfigureContainer(containerBuilder);
});
eventBus.Subscribe<ASC.Core.Common.Notify.IntegrationEvents.Events.NotifySendTelegramMessageRequestedIntegrationEvent, TelegramSendMessageRequestedIntegrationEventHandler>();
var app = builder.Build();
await app.RunWithTasksAsync();
startup.Configure(app, app.Environment);
var eventBus = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<ASC.Core.Common.Notify.IntegrationEvents.Events.NotifySendTelegramMessageRequestedIntegrationEvent, TelegramSendMessageRequestedIntegrationEventHandler>();
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string AppName = Assembly.GetExecutingAssembly().GetName().Name;
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -31,7 +31,7 @@ public static class ConfigurationManagerExtension
public static ConfigurationManager AddWebhookConfiguration(
this ConfigurationManager config)
{
config.AddJsonFile($"appsettings.services.json", true);
config.AddJsonFile($"appsettings.services.json", optional: false, reloadOnChange: true);
return config;
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using NLog;
var options = new WebApplicationOptions
{
Args = args,
@ -32,21 +34,54 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault();
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddWebhookConfiguration()
.AddEnvironmentVariables()
.AddCommandLine(args);
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app);
await app.RunWithTasksAsync();
var logger = NLog.LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => Program.AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
try
{
logger.Info("Configuring web host ({applicationContext})...", Program.AppName);
builder.Host.ConfigureDefault();
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app);
logger.Info("Starting web host ({applicationContext})...", Program.AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", Program.AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1).Replace(".", "");
}

View File

@ -1,25 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwConfigExceptions="false"
autoReload="true">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
<add assembly="NLog.AWS.Logger" />
</extensions>
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<variable name="dir" value="..\Logs\"/>
<variable name="name" value="web"/>
<conversionPattern value=""/>
<variable name="dir" value="..\Logs\"/>
<variable name="name" value="web"/>
<conversionPattern value=""/>
<targets async="true">
<default-target-parameters type="File" maxArchiveDays="30" archiveNumbering="DateAndSequence" archiveEvery="Day" enableArchiveFileCompression="true" archiveAboveSize="52428800" archiveDateFormat="MM-dd" layout="${date:format=yyyy-MM-dd HH\:mm\:ss,fff} ${level:uppercase=true} [${threadid}] ${logger} - ${message} ${exception:format=ToString}"/>
<target name="web" type="File" fileName="${var:dir}${var:name}.log" />
<target name="sql" type="File" fileName="${var:dir}${var:name}.sql.log" layout="${date:universalTime=true:format=yyyy-MM-dd HH\:mm\:ss,fff}|${threadid}|${event-properties:item=elapsed}|${replace:inner=${event-properties:item=commandText}:searchFor=\\r\\n|\\s:replaceWith= :regex=true}|${event-properties:item=parameters}"/>
<target name="ownFile-web" type="File" fileName="${var:dir}${var:name}.asp.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
</targets>
<rules>
<logger name="ASC.SQL" minlevel="Debug" writeTo="sql" final ="true" />
<logger name="ASC*" minlevel="Debug" writeTo="web" />
<logger name="Microsoft.AspNetCore.Hosting.Diagnostics" minlevel="Debug" writeTo="ownFile-web" final="true" />
<logger name="Microsoft.*" maxlevel="Off" final="true" />
</rules>
<targets async="true">
<default-target-parameters type="File" maxArchiveDays="30" archiveNumbering="DateAndSequence" archiveEvery="Day" enableArchiveFileCompression="true" archiveAboveSize="52428800" archiveDateFormat="MM-dd" layout="${date:format=yyyy-MM-dd HH\:mm\:ss,fff} ${level:uppercase=true} [${threadid}] ${logger} - ${message} ${exception:format=ToString}"/>
<target name="web" type="File" fileName="${var:dir}${var:name}.log" />
<target name="sql" type="File" fileName="${var:dir}${var:name}.sql.log" layout="${date:universalTime=true:format=yyyy-MM-dd HH\:mm\:ss,fff}|${threadid}|${event-properties:item=elapsed}|${replace:inner=${event-properties:item=commandText}:searchFor=\\r\\n|\\s:replaceWith= :regex=true}|${event-properties:item=parameters}"/>
<target name="ownFile-web" type="File" fileName="${var:dir}${var:name}.asp.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
<target type="AWSTarget" name="aws" logGroup="/docspace/${var:name}/instance/instance_id/general" region="us-east-1" LibraryLogFileName="">
<layout xsi:type="JsonLayout" includeAllProperties="true">
<attribute name="date" layout="${date:format=yyyy-MM-dd HH\:mm\:ss,fff}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="applicationContext" layout="${application-context}"/>
<attribute name="sourceContext" layout="${logger}"/>
<attribute name="threadId" layout="${threadid}"/>
<attribute name="message" layout="${message}" />
<attribute name="exception" layout="${exception:format=ToString}" />
</layout>
</target>
<target type="AWSTarget" name="aws_sql" logGroup="/docspace/${var:name}/instance/instance_id/sql" region="us-east-1" LibraryLogFileName="">
<layout xsi:type="JsonLayout" includeAllProperties="true">
<attribute name="date" layout="${date:universalTime=true:format=yyyy-MM-dd HH\:mm\:ss,fff}" />
<attribute name="applicationContext" layout="${application-context}"/>
<attribute name="sourceContext" layout="${logger}"/>
<attribute name="threadId" layout="${threadid}"/>
<attribute name="elapsed" layout="${event-properties:item=elapsed}"/>
<attribute name="commandText" layout="${replace:inner=${event-properties:item=commandText}:searchFor=\\r\\n|\\s:replaceWith= :regex=true}" />
</layout>
</target>
</targets>
<rules>
<logger name="ASC.SQL" minlevel="Debug" writeTo="sql" final="true" />
<logger name="ASC*" minlevel="Debug" writeTo="web" />
<logger name="Microsoft.AspNetCore.Hosting.Diagnostics" minlevel="Debug" writeTo="ownFile-web" final="true" />
<logger name="Microsoft.*" maxlevel="Off" final="true" />
</rules>
</nlog>

View File

@ -4,8 +4,8 @@
"Archives": "Arxivlər",
"BackToParentFolderButton": "Ana qovluğa qayıt",
"ByAuthor": "Müəllif",
"ByCreationDate": "Yaradıldı",
"ByLastModifiedDate": "Dəyişdirilib",
"ByCreation": "Yaradıldı",
"ByLastModified": "Dəyişdirilib",
"ByTitle": "Başlıq",
"CommonEmptyContainerDescription": "'Ümumi' bölməsi portal inzibatçısı tərəfindən bütün istifadəçilərlə paylaşılan faylları ehtiva edir. Orada yalnız portal inzibatçıları fayl yarada bilər. İstifadəçilərə bölmə daxilində müəyyən bir qovluğa tam giriş verilə bilər. Bu şəkildə bu qovluqda fayllar yarada/yükləyə biləcəklər.",
"ContainsSpecCharacter": "Başlıqda aşağıdakı simvollardan heç biri ola bilməz: *+: \"<>? |/ ",

View File

@ -4,8 +4,8 @@
"Archives": "Архиви",
"BackToParentFolderButton": "Обратно към родителската папка",
"ByAuthor": "Автор",
"ByCreationDate": "Създаден",
"ByLastModifiedDate": "Модифициран",
"ByCreation": "Създаден",
"ByLastModified": "Модифициран",
"ByTitle": "Заглавие",
"CommonEmptyContainerDescription": "Разделът 'Често срещани' съдържа файлове, които са споделени с всички потребители от администратора на портала. Само администраторите на портала могат да създават файлове там. Потребителите могат да се сдобият с Пълен достъп до определена папка в рамките на раздела. По този начин те ще могат да създават/качват файлове във всяка папка.",
"ContainsSpecCharacter": "Заглавието не може да съдържа някой от следните символи: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Archivy",
"BackToParentFolderButton": "Zpět do nadřazené složky",
"ByAuthor": "Autor",
"ByCreationDate": "Vytvořeno",
"ByLastModifiedDate": "Upraveno",
"ByCreation": "Vytvořeno",
"ByLastModified": "Upraveno",
"ByTitle": "Název",
"CommonEmptyContainerDescription": "Sekce 'Sdílené' obsahuje soubory, které správce portálu sdílí se všemi uživateli. Soubory v ní mohou vytvářet pouze správci portálu. Uživatelům lze v rámci sekce udělit plný přístup k určité složce. Tímto způsobem budou moci vytvářet/nahrávat soubory právě v této složce. ",
"ContainsSpecCharacter": "Název nesmí obsahovat žádný z následujících znaků: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Archive",
"BackToParentFolderButton": "Zurück zum übergeordneten Ordner",
"ByAuthor": "Verfasser",
"ByCreationDate": "Erstellt",
"ByLastModifiedDate": "Verändert",
"ByCreation": "Erstellt",
"ByLastModified": "Verändert",
"ByTitle": "Titel",
"CommonEmptyContainerDescription": "In gemeinsamen Dokumenten finden Sie Dateien, auf denen alle Benutzer Zugriff haben. Nur Portaladministratoren können dort Dateien erstellen. Benutzern kann der vollständigen Zugriff auf einen bestimmten Ordner innerhalb des Abschnitts erteilt werden. Dann können Sie Dateien in diesem Ordner erstellen / hochladen.",
"ContainsSpecCharacter": "Der Titel darf diese Symbole nicht beinhalten: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Αρχειοθετήσεις",
"BackToParentFolderButton": "Επιστροφή στον γονικό φάκελο",
"ByAuthor": "Δημιουργός",
"ByCreationDate": "Δημιουργήθηκε",
"ByLastModifiedDate": "Τροποποιήθηκε",
"ByCreation": "Δημιουργήθηκε",
"ByLastModified": "Τροποποιήθηκε",
"ByTitle": "Τίτλος",
"CommonEmptyContainerDescription": "Η ενότητα «Κοινά» περιέχει αρχεία που μοιράζονται σε όλους τους χρήστες από τον διαχειριστή της πύλης. Μόνο οι διαχειριστές της πύλης μπορούν να δημιουργήσουν αρχεία εκεί. Οι χρήστες μπορούν να έχουν πλήρη πρόσβαση σε έναν συγκεκριμένο φάκελο εντός της ενότητας. Έτσι, θα μπορούν να δημιουργούν/μεταφορτώνουν αρχεία σε αυτόν τον φάκελο.",
"ContainsSpecCharacter": "Ο τίτλος δεν μπορεί να περιέχει τους ακόλουθους χαρακτήρες: *+:\"<>?|/",

View File

@ -1,5 +1,5 @@
{
"AdvancedFilter": "Advanced search options",
"AdvancedFilter": "Search options",
"All": "All",
"AllFiles": "All files",
"Archives": "Archives",
@ -7,8 +7,8 @@
"ArchiveEmptyScreenHeader": "No archived rooms here yet",
"BackToParentFolderButton": "Back to parent folder",
"ByAuthor": "Author",
"ByCreationDate": "Created",
"ByLastModifiedDate": "Modified",
"ByCreation": "Created",
"ByLastModified": "Modified",
"ByOwner": "Owner",
"ByTitle": "Title",
"CollaborationRooms": "Collaboration",
@ -26,7 +26,9 @@
"EmptyFolderHeader": "No files in this folder",
"EmptyRecycleBin": "Empty Trash",
"EmptyScreenFolder": "No docs here yet",
"ExcludeSubfolders": "Exclude subfolders",
"FavoritesEmptyContainerDescription": "To mark files as favorites or remove them from this list, use the context menu.",
"FileContents": "File contents",
"FileRemoved": "File moved to Trash",
"FileRenamed": "The document '{{oldTitle}}' is renamed to '{{newTitle}}'",
"FillingFormRooms": "Filling form",
@ -35,6 +37,7 @@
"Folder": "Folder",
"FolderRemoved": "Folder moved to Trash",
"FolderRenamed": "The folder '{{folderTitle}}' is renamed to '{{newFoldedTitle}}'",
"Forms": "Forms",
"FromArchive": "Move from archive",
"GoToMyButton": "Go to My Documents",
"GoToShared": "Go to Shared",
@ -43,6 +46,7 @@
"MarkAsFavorite": "Mark as favorite",
"MarkRead": "Mark as read",
"MarkedAsFavorite": "Added to favorites",
"FormsTemplates": "Forms templates",
"Media": "Media",
"MoveItem": "<strong>{{title}}</strong> moved",
"MoveItems": "<strong>{{qty}}</strong> elements have been moved",
@ -77,6 +81,7 @@
"ReviewRooms": "Review",
"RoomRemoved": "Room removed",
"RoomsRemoved": "Rooms removed",
"SearchByContent": "Search by file contents",
"SendByEmail": "Send by email",
"Share": "Share",
"SharedEmptyContainerDescription": "The 'Shared with Me' section shows files shared to you by teammates. If you haven't seen the latest changes, they are marked as new. You can remove the files from the list using the context menu. ",
@ -96,5 +101,6 @@
"VersionHistory": "Version history",
"ViewList": "List",
"ViewOnlyRooms": "View-only",
"ViewTiles": "Tiles"
"ViewTiles": "Tiles",
"WithSubfolders": "With subfolders"
}

View File

@ -1,6 +1,7 @@
{
"AdditionalSections": "Additional sections",
"Clouds": "Clouds",
"CommonSettings": "Common settings",
"CommonSettings": "Common",
"ConnectAdminDescription": "For successful connection, enter the necessary data on <1>this page</1>.",
"ConnectCloud": "Connect cloud",
"ConnectDescriptionText": "You haven't connected any third-party clouds yet.",
@ -15,8 +16,10 @@
"IntermediateVersion": "Keep all saved intermediate versions",
"KeepIntermediateVersion": "Keep intermediate versions when editing",
"OriginalCopy": "Save the file copy in the original format as well",
"StoringFileVersion": "Storing file versions",
"ThirdPartyAccounts": "Third-party accounts",
"ThirdPartyBtn": "Allow users to connect third-party storages",
"ThirdPartySettings": "Connected clouds",
"UpdateOrCreate": "Update the file version for the existing file with the same name. Otherwise, a copy of the file will be created."
"UpdateOrCreate": "Update the file version for the existing file with the same name. Otherwise, a copy of the file will be created.",
"StoringFileVersion": "Storing file versions"
}

View File

@ -4,8 +4,8 @@
"Archives": "Archivos",
"BackToParentFolderButton": "Volver a la carpeta principal",
"ByAuthor": "Autor",
"ByCreationDate": "Creado",
"ByLastModifiedDate": "Modificado",
"ByCreation": "Creado",
"ByLastModified": "Modificado",
"ByTitle": "Título",
"CommonEmptyContainerDescription": "La sección 'Documentos comunes' contiene archivos compartidos por el administrador del portal con todos los usuarios. Sólo los administradores del portal pueden crear archivos allí. Los usuarios pueden tener acceso completo a una determinada carpeta dentro de la sección. De esta manera podrán crear/subir archivos en esta misma carpeta. ",
"ContainsSpecCharacter": "El título no puede contener ninguno de los siguientes caracteres: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arkistot",
"BackToParentFolderButton": "Takaisin pääkansioon",
"ByAuthor": "Tekijä",
"ByCreationDate": "Luotu",
"ByLastModifiedDate": "Muokattu",
"ByCreation": "Luotu",
"ByLastModified": "Muokattu",
"ByTitle": "Otsikko",
"CommonEmptyContainerDescription": "Yleinen -osio sisältää tiedostoja, jotka portaalin ylläpitäjä on jakanut kaikille käyttäjille. Vain portaalin ylläpitäjät voivat luoda tiedostoja sinne. Käyttäjille voidaan myöntää täysi käyttöoikeus tiettyyn osion kansioon. Tällä tavalla he voivat luoda/ladata tiedostoja juuri tähän kansioon. ",
"ContainsSpecCharacter": "Otsikko ei voi sisältää mitään seuraavista merkeistä: *+: \"<>? |/",

View File

@ -4,8 +4,8 @@
"Archives": "Archives",
"BackToParentFolderButton": "Retour vers le dossier précédent",
"ByAuthor": "Auteur",
"ByCreationDate": "Créé",
"ByLastModifiedDate": "Modifié",
"ByCreation": "Créé",
"ByLastModified": "Modifié",
"ByTitle": "Titre",
"CommonEmptyContainerDescription": "La section \"Documents Communs\" contient des fichiers partagés par l'administrateur du portail avec tous les utilisateurs. Seuls les administrateurs du portail peuvent y créer des fichiers. Les utilisateurs peuvent obtenir un accès complet à un certain dossier de la section. Ainsi, ils pourront créer/télécharger des fichiers dans ce même dossier. ",
"ContainsSpecCharacter": "Le titre ne peut contenir aucun des caractères suivants : *+ :\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Արխիվներ",
"BackToParentFolderButton": "Վերադառնալ ծնող պանակ",
"ByAuthor": "Հեղինակ",
"ByCreationDate": "Ստեղծված",
"ByLastModifiedDate": "Փոփոխված",
"ByCreation": "Ստեղծված",
"ByLastModified": "Փոփոխված",
"ByTitle": "Անվանում",
"CommonEmptyContainerDescription": "'Ընդհանուր'բաժինը պարունակում է ֆայլեր, որոնք կայքէջի ադմինիստրատորի կողմից համօգտագործվում են բոլոր օգտատերերին: Միայն կայքէջի ադմինիստրատորները կարող են այնտեղ ֆայլեր ստեղծել։ Օգտագործողներին կարող է տրվել ամբողջական մուտք դեպի որոշակի պանակ այս բաժնում: Այս կերպ նրանք կկարողանան ստեղծել/վերբեռնել ֆայլեր հենց այս պանակում:",
"ContainsSpecCharacter": "Վերնագիրը չի կարող պարունակել հետևյալ նիշերից որևէ մեկը՝ *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Archivi",
"BackToParentFolderButton": "Vai alla cartella superiore",
"ByAuthor": "Autore",
"ByCreationDate": "Creato",
"ByLastModifiedDate": "Modificato",
"ByCreation": "Creato",
"ByLastModified": "Modificato",
"ByTitle": "Titolo",
"CommonEmptyContainerDescription": "La sezione \"Comune\" contiene i file condivisi con tutti gli utenti di tipo amministratore del portale. Solo gli amministratori del portale possono creare file nel posto \"Comune\". Agli utenti può essere concesso l'accesso completo a una determinata cartella all'interno della sezione. In questo modo potranno creare / caricare file in questa stessa cartella.",
"ContainsSpecCharacter": "Il titolo non può contenere nessuno dei seguenti caratteri: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "アーカイブ",
"BackToParentFolderButton": "親フォルダに戻る",
"ByAuthor": "作成者",
"ByCreationDate": "作成",
"ByLastModifiedDate": "変更",
"ByCreation": "作成",
"ByLastModified": "変更",
"ByTitle": "タイトル",
"CommonEmptyContainerDescription": "「共通」セクションには、ポータル管理者が全ユーザに共有するファイルがあります。ここにファイルを作成できるのは、ポータル管理者のみです。ユーザーは、セクション内の特定のフォルダへのフルアクセスを許可することができます。この場合、ユーザーは、このフォルダにファイルを作成/アップロードすることができます。 ",
"ContainsSpecCharacter": "タイトルには以下の文字*+:\"<>?|/は使用できません。",

View File

@ -4,8 +4,8 @@
"Archives": "아카이브",
"BackToParentFolderButton": "상위 폴더로 돌아가기",
"ByAuthor": "생성자",
"ByCreationDate": "생성일",
"ByLastModifiedDate": "수정일",
"ByCreation": "생성일",
"ByLastModified": "수정일",
"ByTitle": "제목",
"CommonEmptyContainerDescription": "'공통' 섹션은 포털 관리자에 의해 모든 사용자에게 공유된 파일을 포함합니다. 포털 관리자만 공통 섹션에 파일을 생성할 수 있습니다. 사용자는 해당 섹션 내 특정 폴더에 대한 전체 액세스 권한을 부여 받을 수 있습니다. 그리고 이러한 방식으로 해당 폴더에 파일을 생성/업로드할 수 있습니다.",
"ContainsSpecCharacter": "제목에는 다음 문자가 포함될 수 없습니다: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "ຮວບຮວມ",
"BackToParentFolderButton": "ກັບໄປທີ່ແຟ້ມຫຼັກ",
"ByAuthor": "ຜູ້ຂຽນ",
"ByCreationDate": "ສ້າງ",
"ByLastModifiedDate": "ແກ້ໄຂ",
"ByCreation": "ສ້າງ",
"ByLastModified": "ແກ້ໄຂ",
"ByTitle": "ຫົວຂໍ້",
"CommonEmptyContainerDescription": "ສ່ວນ common 'ມີເອກະສານທີ່ແບ່ງປັນໃຫ້ຜູ້ຊົມໃຊ້ທັງໝົດ ໂດຍ Portal admin. ມີພຽງແຕ່ Portal ເປັນຜູ້ຮັບຮອງເທົ່ານັ້ນທີ່ສາມາດສ້າງເອກະສານຢູ່ບ່ອນນັ້ນ. ຜູ້ໃຊ້ສາມາດໄດ້ຮັບການອະນຸຍາດເຂົ້າເຖິງໂຟນເດີທີ່ແນ່ນອນພາຍໃນພາກສ່ວນໃດໜື່ງ. ວິທີນີ້ພວກເຂົາຈະສາມາດສ້າງ / ອັບໂຫລດເອກະສານໃນໂຟນເດີນັ້ນໄດ້.",
"ContainsSpecCharacter": "ຫົວຂໍ້ບໍ່ສາມາດມີຕົວອັກສອນຕໍ່ໄປນີ້: * +: \"<>? | /",

View File

@ -4,8 +4,8 @@
"Archives": "Arhīvi",
"BackToParentFolderButton": "Atpakaļ uz vecāku mapi",
"ByAuthor": "Autors",
"ByCreationDate": "Izveidots",
"ByLastModifiedDate": "Modificēts",
"ByCreation": "Izveidots",
"ByLastModified": "Modificēts",
"ByTitle": "Nosaukums",
"CommonEmptyContainerDescription": "Sadaļā 'Kopējs' ir faili, kurus visiem lietotājiem ir kopīgojis portāla administrators. Failus tur var izveidot tikai portāla administratori. Lietotājiem var piešķirt pilnu piekļuvi noteiktai sadaļas mapei. Tādā veidā viņi varēs izveidot/augšupielādēt failus tieši šajā mapē. ",
"ContainsSpecCharacter": "Nosaukumā nedrīkst būt neviena no šīm rakstzīmēm: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Archieven",
"BackToParentFolderButton": "Terug naar bovenliggende map",
"ByAuthor": "Auteur",
"ByCreationDate": "Aangemaakt",
"ByLastModifiedDate": "Gewijzigd",
"ByCreation": "Aangemaakt",
"ByLastModified": "Gewijzigd",
"ByTitle": "Titel",
"CommonEmptyContainerDescription": "'Algemene' sectie bevat bestanden die door de portaal beheerder worden gedeeld met alle gebruikers. Alleen portaal beheerders kunnen daar bestanden aanmaken. Gebruikers kunnen volledige toegang krijgen tot een bepaalde map binnen de sectie. Op deze manier kunnen ze bestanden maken/uploaden in deze map. ",
"ContainsSpecCharacter": "De titel mag geen van de volgende tekens bevatten: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Archiwa",
"BackToParentFolderButton": "Wróć do folderu nadrzędnego",
"ByAuthor": "Autor",
"ByCreationDate": "Utworzono",
"ByLastModifiedDate": "Zmodyfikowano",
"ByCreation": "Utworzono",
"ByLastModified": "Zmodyfikowano",
"ByTitle": "Tytuł",
"CommonEmptyContainerDescription": "Sekcja 'Wspólne' zawiera pliki udostępnione wszystkim użytkownikom przez administratora portalu. Tylko on może tworzyć w niej nowe pliki. Użytkownicy mogą uzyskać pełen dostęp do pewnych folderów znajdujących się w tej sekcji. Dzięki temu będą w stanie tworzyć/wgrywać w nich dowolne pliki. ",
"ContainsSpecCharacter": "Tytuł nie może zawierać następujących znaków: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arquivos",
"BackToParentFolderButton": "Voltar para pasta principal",
"ByAuthor": "Autor",
"ByCreationDate": "Criado",
"ByLastModifiedDate": "Modificado",
"ByCreation": "Criado",
"ByLastModified": "Modificado",
"ByTitle": "Titulo",
"CommonEmptyContainerDescription": "A seção 'Comum' contém arquivos compartilhados a todos os usuários pelo administrador do portal. Somente os administradores do portal podem criar arquivos lá. Os usuários podem ter acesso total a uma determinada pasta dentro da seção. Desta forma, eles poderão criar/enviar arquivos nesta mesma pasta.",
"ContainsSpecCharacter": "O título não pode conter nenhum dos seguintes caracteres: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arquivos",
"BackToParentFolderButton": "Voltar à pasta principal",
"ByAuthor": "Autor",
"ByCreationDate": "Criado",
"ByLastModifiedDate": "Modificado",
"ByCreation": "Criado",
"ByLastModified": "Modificado",
"ByTitle": "Titulo",
"CommonEmptyContainerDescription": "A secção 'Comum' contém ficheiro partilhados a todos os utilizadores pelo administrador do portal. Apenas os administradores do portal podem criar lá ficheiros. Os utilizadores podem ter acesso total a uma determinada pasta dentro da secção. Desta forma, eles poderão criar/enviar ficheiros nesta mesma pasta.",
"ContainsSpecCharacter": "O título não pode conter nenhum dos seguintes caracteres: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arhive",
"BackToParentFolderButton": "Revenire la folderul părinte",
"ByAuthor": "Autor",
"ByCreationDate": "A fost creat la",
"ByLastModifiedDate": "Modificat",
"ByCreation": "A fost creat la",
"ByLastModified": "Modificat",
"ByTitle": "Titlu",
"CommonEmptyContainerDescription": "Secțiunea Comune conține fișiere partajate cu alți utilizatori de către administratorul portalului. Numai administratorii portalului pot crea fișiere acolo. Utilizatorii pot primi acces complet la un anumit dosar din secțiunea. În acest mod, utilizatorii pot crea/încărca fișiere în acest dosar.",
"ContainsSpecCharacter": "Numele nu poate conține niciun din caractere următoare: *+:\"<>?|/ ",

View File

@ -4,8 +4,8 @@
"Archives": "Архивы",
"BackToParentFolderButton": "Вернуться в папку на уровень выше",
"ByAuthor": "Автор",
"ByCreationDate": "Создан",
"ByLastModifiedDate": "Изменен",
"ByCreation": "Создан",
"ByLastModified": "Изменен",
"ByTitle": "Название",
"CollaborationRooms": "Совместное редактирование",
"CommonEmptyContainerDescription": "В разделе «Общие документы» отображаются все документы, которыми администратор портала предоставил общий доступ. Только администраторы портала могут создавать папки в этом разделе, но с предоставленным доступом пользователи портала также могут загружать свои файлы здесь. Перетащите файлы со своего компьютера сюда, чтобы загрузить их на свой портал еще проще.",

View File

@ -1,6 +1,7 @@
{
"AdditionalSections": "Дополнительные разделы",
"Clouds": "Облака",
"CommonSettings": "Общие настройки",
"CommonSettings": "Общие",
"ConnectAdminDescription": "Для успешного подключения введите нужные данные на <1>этой странице</1>.",
"ConnectCloud": "Подключить облако",
"ConnectDescriptionText": "Вы еще не подключили сторонние облачные сервисы.",
@ -15,8 +16,9 @@
"IntermediateVersion": "Хранить все сохраненные промежуточные версии",
"KeepIntermediateVersion": "Хранить промежуточные версии при редактировании",
"OriginalCopy": "Сохранять также копию файла в исходном формате",
"StoringFileVersion": "Хранение версий файлов",
"ThirdPartyAccounts": "Сторонние аккаунты",
"ThirdPartyBtn": "Разрешить пользователям подключать сторонние хранилища",
"ThirdPartySettings": "Подключенные облака",
"UpdateOrCreate": "Обновлять версию файла для существующего файла с таким же именем. В противном случае будет создаваться копия файла."
"UpdateOrCreate": "Обновлять версию файла для существующего файла с таким же именем. В противном случае будет создаваться копия файла.",
"StoringFileVersion": "Хранение версий файлов"
}

View File

@ -4,8 +4,8 @@
"Archives": "Archívy",
"BackToParentFolderButton": "Späť do nadradeného priečinka",
"ByAuthor": "Autor",
"ByCreationDate": "Vytvorené",
"ByLastModifiedDate": "Upravené",
"ByCreation": "Vytvorené",
"ByLastModified": "Upravené",
"ByTitle": "Názov",
"CommonEmptyContainerDescription": "Sekcia 'Spoločné' obsahuje súbory zdieľané všetkým používateľom správcom portálu. Súbory tam môžu vytvárať iba správcovia portálu. Používateľom môže byť udelený úplný prístup k určitému priečinku v rámci sekcie. Týmto spôsobom budú môcť vytvárať/nahrávať súbory práve do tohto priečinka.",
"ContainsSpecCharacter": "Názov nemôže obsahovať žiadne z nasledujúcich znakov: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arhivi",
"BackToParentFolderButton": "Nazaj na starševsko mapo",
"ByAuthor": "Avtor",
"ByCreationDate": "Ustvarjeno",
"ByLastModifiedDate": "Popravljeno",
"ByCreation": "Ustvarjeno",
"ByLastModified": "Popravljeno",
"ByTitle": "Naslov",
"CommonEmptyContainerDescription": "'Skupen' razdelek vsebuje datoteke, ki jih skrbnik portala deli z vsemi uporabniki. Samo skrbniki portala lahko tam ustvarjajo datoteke. Uporabniki lahko dobijo popoln dostop do določene mape v razdelku. Tako bodo lahko ustvarili/naložili datoteke ravno v tej mapi. ",
"ContainsSpecCharacter": "Naslov ne sme vsebovati nobenega od naslednjih znakov: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Arşivler",
"BackToParentFolderButton": "Üst klasöre geri dön",
"ByAuthor": "Yazar",
"ByCreationDate": "Oluşturuldu",
"ByLastModifiedDate": "Değiştirilmiş",
"ByCreation": "Oluşturuldu",
"ByLastModified": "Değiştirilmiş",
"ByTitle": "Başlık",
"CommonEmptyContainerDescription": "'Ortak' bölüm, portal yöneticisi tarafından tüm kullanıcılarla paylaşılan dosyaları içerir. Burada yalnızca portal yöneticileri dosya oluşturabilir. Bu bölüm içinde kullanıcılara belirli bir klasöre Tam erişim verilebilir. Bu şekilde, bu klasörde dosya oluşturabilecek/yükleyebileceklerdir.",
"ContainsSpecCharacter": "Başlık şu karakterlerden herhangi birini içeremez:: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Архіви",
"BackToParentFolderButton": "Назад до батьківської папки",
"ByAuthor": "Автор",
"ByCreationDate": "Створено",
"ByLastModifiedDate": "Змінено",
"ByCreation": "Створено",
"ByLastModified": "Змінено",
"ByTitle": "Заголовок",
"CommonEmptyContainerDescription": "Розділ \"Загальне\" містить файли, до яких адміністратор порталу надав доступ усім користувачам. Тільки адміністратори порталу можуть створювати тут файли. Користувачам може бути наданий повний доступ до певної папки в розділі. Це дозволить їм створювати файли в цій папці та передавати їх до неї.",
"ContainsSpecCharacter": "Заголовок не може містити жодного з цих символів: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "Lưu trữ",
"BackToParentFolderButton": "Quay lại thư mục gốc",
"ByAuthor": "Tác giả",
"ByCreationDate": "Đã tạo",
"ByLastModifiedDate": "Đã sửa đổi",
"ByCreation": "Đã tạo",
"ByLastModified": "Đã sửa đổi",
"ByTitle": "Tiêu đề",
"CommonEmptyContainerDescription": "Phần Chung chứa các tệp được quản trị viên cổng thông tin chia sẻ cho tất cả người dùng. Chỉ quản trị viên cổng thông tin mới có thể tạo ệp ở đó. Người dùng có thể được cấp toàn quyền truy cập vào một thư mục nhất định trong phần này. Bằng cách này họ sẽ có thể tạo/tải lên các tệp trong chính thư mục này.",
"ContainsSpecCharacter": "Tiêu đề không được chứa bất kỳ ký tự nào sau đây: *+:\"<>?|/",

View File

@ -4,8 +4,8 @@
"Archives": "归档",
"BackToParentFolderButton": "返回父文件夹",
"ByAuthor": "作者",
"ByCreationDate": "创建日期",
"ByLastModifiedDate": "修改日期",
"ByCreation": "创建日期",
"ByLastModified": "修改日期",
"ByTitle": "标题",
"CommonEmptyContainerDescription": "'Common'部分包含由门户管理员分享给所有用户的文件。仅门户管理员可在此处创建文件。用户将被授予该部分中特定文件夹的完整访问权限。这样其就能在该文件夹中创建/上传文件了。",
"ContainsSpecCharacter": "标题中不得包含任意以下字符:*+:\"<>?|/",

View File

@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { observer, inject } from "mobx-react";
import { Events } from "@docspace/client/src/helpers/filesConstants";
import { Events } from "@docspace/common/constants";
import toastr from "@docspace/components/toast/toastr";
import throttle from "lodash/throttle";

View File

@ -447,7 +447,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
"/settings",
"/settings/common",
"/settings/admin",
"/settings/connected-clouds",
//"/settings/connected-clouds",
]}
component={FilesRoute}
/>

View File

@ -13,7 +13,7 @@ import SettingsItem from "./SettingsItem";
import AccountsItem from "./AccountsItem";
import { combineUrl } from "@docspace/common/utils";
import { isDesktop, isTablet, isMobileOnly } from "react-device-detect";
import ThirdPartyList from "./ThirdPartyList";
//import ThirdPartyList from "./ThirdPartyList";
import DownloadAppList from "./DownloadAppList";
import Banner from "./Banner";
import { showLoader, hideLoader } from "@docspace/common/utils";
@ -39,14 +39,16 @@ const ArticleBodyContent = (props) => {
firstLoad,
showText,
isDesktopClient,
enableThirdParty,
isVisitor,
// enableThirdParty,
// isVisitor,
FirebaseHelper,
theme,
toggleArticleOpen,
categoryType,
isAdmin,
filesIsLoading,
roomsFolderId,
archiveFolderId,
} = props;
const campaigns = (localStorage.getItem("campaigns") || "")
@ -65,8 +67,6 @@ const ArticleBodyContent = (props) => {
homepage,
history,
roomsFolderId,
archiveFolderId,
} = props;
if (filesIsLoading) return;
@ -144,7 +144,7 @@ const ArticleBodyContent = (props) => {
});
}
},
[categoryType]
[categoryType, roomsFolderId, archiveFolderId]
);
const onShowNewFilesPanel = React.useCallback((folderId) => {
@ -163,7 +163,7 @@ const ArticleBodyContent = (props) => {
{!personal && !firstLoad && <SettingsItem />}
{!isDesktopClient && showText && !docSpace && (
<StyledBlock showText={showText}>
{enableThirdParty && !isVisitor && <ThirdPartyList />}
{/* {enableThirdParty && !isVisitor && <ThirdPartyList />} */}
<DownloadAppList theme={theme} />
{(isDesktop || isTablet) &&
personal &&

View File

@ -14,7 +14,7 @@ import MobileView from "./MobileView";
import { combineUrl } from "@docspace/common/utils";
import config from "PACKAGE_FILE";
import withLoader from "../../../HOCs/withLoader";
import { Events } from "@docspace/client/src/helpers/filesConstants";
import { Events } from "@docspace/common/constants";
import { getMainButtonItems } from "SRC_DIR/helpers/plugins";
import toastr from "@docspace/components/toast/toastr";

View File

@ -8,16 +8,19 @@ import Box from "@docspace/components/box";
const EmptyFolderContainer = ({
t,
onCreate,
filter,
fetchFiles,
fetchRooms,
setIsLoading,
parentId,
linkStyles,
isRooms,
}) => {
const onBackToParentFolder = () => {
const newFilter = filter.clone();
setIsLoading(true);
fetchFiles(parentId, newFilter).finally(() => setIsLoading(false));
isRooms
? fetchRooms(parentId).finally(() => setIsLoading(false))
: fetchFiles(parentId).finally(() => setIsLoading(false));
};
const buttons = (
@ -85,12 +88,21 @@ const EmptyFolderContainer = ({
};
export default inject(({ filesStore, selectedFolderStore }) => {
const { filter, fetchFiles } = filesStore;
const { fetchFiles, fetchRooms } = filesStore;
const { navigationPath, parentId } = selectedFolderStore;
let isRootRoom, isRoom, id;
if (navigationPath && navigationPath.length) {
isRootRoom = navigationPath.at(-1).isRootRoom;
isRoom = navigationPath.at(-1).isRoom;
id = navigationPath.at(-1).id;
}
return {
filter,
fetchFiles,
fetchRooms,
setIsLoading: filesStore.setIsLoading,
parentId: selectedFolderStore.parentId,
parentId: id ?? parentId,
isRooms: isRoom || isRootRoom,
};
})(withTranslation(["Files", "Translations"])(observer(EmptyFolderContainer)));

View File

@ -5,7 +5,7 @@ import EmptyFilterContainer from "./EmptyFilterContainer";
import EmptyFolderContainer from "./EmptyFolderContainer";
import { FileAction } from "@docspace/common/constants";
import { isMobile } from "react-device-detect";
import { Events } from "@docspace/client/src/helpers/filesConstants";
import { Events } from "@docspace/common/constants";
const linkStyles = {
isHovered: true,

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback, memo } from "react";
import { FileAction } from "@docspace/common/constants";
import { Events } from "@docspace/client/src/helpers/filesConstants";
import { Events } from "@docspace/common/constants";
import CreateEvent from "./CreateEvent";
import RenameEvent from "./RenameEvent";

View File

@ -153,6 +153,7 @@ const PureConnectDialogContainer = (props) => {
loginValue,
passwordValue,
oAuthToken,
false,
customerTitle,
provider_key || key,
provider_id,

View File

@ -26,6 +26,7 @@ const FilesListBody = ({
page,
folderSelection,
getIcon,
maxHeight = 384,
}) => {
const { t } = useTranslation(["SelectFile", "Common"]);
const [isLoading, setIsLoading] = useState(false);
@ -177,7 +178,7 @@ const FilesListBody = ({
{({ onItemsRendered, ref }) => (
<List
theme={theme}
height={384}
height={maxHeight}
itemCount={itemCount}
itemSize={48}
onItemsRendered={onItemsRendered}

Some files were not shown because too many files have changed in this diff Show More