Merge branch 'develop' into feature/recalculate-user-quota

This commit is contained in:
Nikolay Rechkin 2022-10-25 17:33:56 +03:00
commit 128527a809
337 changed files with 33298 additions and 28935 deletions

View File

@ -22,6 +22,7 @@
"common\\ASC.Notify.Textile\\ASC.Notify.Textile.csproj",
"common\\ASC.Textile\\ASC.Textile.csproj",
"common\\ASC.Webhooks.Core\\ASC.Webhooks.Core.csproj",
"common\\services\\ASC.ApiSystem\\ASC.ApiSystem.csproj",
"common\\services\\ASC.AuditTrail\\ASC.AuditTrail.csproj",
"common\\services\\ASC.ClearEvents\\ASC.ClearEvents.csproj",
"common\\services\\ASC.Data.Backup.BackgroundTasks\\ASC.Data.Backup.BackgroundTasks.csproj",

View File

@ -20,8 +20,9 @@ docker_dir="$( pwd )"
echo "Docker directory:" $docker_dir
docker_file=Dockerfile.dev
core_base_domain="localhost"
build_date=$(date +%Y-%m-%d)
env_extension="dev"
echo "BUILD DATE: $build_date"
@ -40,6 +41,9 @@ echo "SERVICE_CLIENT: $client"
echo "Stop all backend services"
$dir/build/start/stop.backend.docker.sh
echo "Remove all docker images except 'mysql, rabbitmq, redis, elasticsearch, documentserver'"
docker image rm -f $(docker images -a | egrep "onlyoffice" | egrep -v "mysql|rabbitmq|redis|elasticsearch|documentserver" | awk 'NR>0 {print $3}')
echo "Run MySQL"
arch_name="$(uname -m)"
@ -74,6 +78,8 @@ GIT_BRANCH=$branch \
SERVICE_DOCEDITOR=$doceditor \
SERVICE_LOGIN=$login \
SERVICE_CLIENT=$client \
APP_CORE_BASE_DOMAIN=$core_base_domain \
ENV_EXTENSION=$env_extension \
docker compose -f build.dev.yml build --build-arg GIT_BRANCH=$branch --build-arg RELEASE_DATE=$build_date
echo "Run DB migration"

View File

@ -35,7 +35,7 @@ RUN apt-get -y update && \
rm -rf /var/lib/apt/lists/*
RUN echo ${GIT_BRANCH} && \
git clone --depth 1 --recurse-submodules -b ${GIT_BRANCH} https://github.com/ONLYOFFICE/DocSpace.git ${SRC_PATH}
git clone --recurse-submodules -b ${GIT_BRANCH} https://github.com/ONLYOFFICE/DocSpace.git ${SRC_PATH}
RUN cd ${SRC_PATH} && \
# mkdir -p /app/onlyoffice/config/ && cp -rf config/* /app/onlyoffice/config/ && \

View File

@ -35,7 +35,7 @@ RUN apt-get -y update && \
rm -rf /var/lib/apt/lists/*
RUN echo ${GIT_BRANCH} && \
git clone --depth 1 --recurse-submodules -b ${GIT_BRANCH} https://github.com/ONLYOFFICE/DocSpace.git ${SRC_PATH}
git clone --recurse-submodules -b ${GIT_BRANCH} https://github.com/ONLYOFFICE/DocSpace.git ${SRC_PATH}
RUN cd ${SRC_PATH} && \
mkdir -p /app/onlyoffice/ && \

View File

@ -12,6 +12,8 @@ services:
user: mysql
expose:
- "3306"
ports:
- 33060:3306
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}

View File

@ -23,7 +23,7 @@ MYSQL_USER = os.environ["MYSQL_USER"] if environ.get("MYSQL_USER") else "onlyoff
MYSQL_PASSWORD = os.environ["MYSQL_PASSWORD"] if environ.get("MYSQL_PASSWORD") else "onlyoffice_pass"
DATABASE_MIGRATION = os.environ["DATABASE_MIGRATION"] if environ.get("DATABASE_MIGRATION") else "false"
APP_CORE_BASE_DOMAIN = os.environ["APP_CORE_BASE_DOMAIN"] if environ.get("APP_CORE_BASE_DOMAIN") else "localhost"
APP_CORE_BASE_DOMAIN = os.environ["APP_CORE_BASE_DOMAIN"] if environ.get("APP_CORE_BASE_DOMAIN") is not None else "localhost"
APP_CORE_MACHINEKEY = os.environ["APP_CORE_MACHINEKEY"] if environ.get("APP_CORE_MACHINEKEY") else "your_core_machinekey"
APP_URL_PORTAL = os.environ["APP_URL_PORTAL"] if environ.get("APP_URL_PORTAL") else "http://" + ROUTER_HOST + ":8092"
APP_STORAGE_ROOT = os.environ["APP_STORAGE_ROOT"] if environ.get("APP_STORAGE_ROOT") else BASE_DIR + "/data/"

View File

@ -0,0 +1,8 @@
rd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "Run script directory:" $dir
dir=$(builtin cd $rd/../; pwd)
echo "Root directory:" $dir
dotnet test $dir/common/Tests/Frontend.Translations.Tests/Frontend.Translations.Tests.csproj --filter "TestCategory=FastRunning" -l:html -r $dir/TestsResults

4
build/run/ApiSystem.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
PUSHD %~dp0..\..
set servicepath=%cd%\common\services\ASC.ApiSystem\bin\Debug\ASC.ApiSystem.exe urls=http://0.0.0.0:5010 $STORAGE_ROOT=%cd%\Data log:dir=%cd%\Logs log:name=apisystem pathToConf=%cd%\config core:products:folder=%cd%\products

View File

@ -35,16 +35,19 @@ echo "SERVICE_DOCEDITOR: $doceditor"
echo "SERVICE_LOGIN: $login"
echo "SERVICE_CLIENT: $client"
docker_file=Dockerfile.dev
env_extension="dev"
core_base_domain="localhost"
echo "Start all backend services"
DOCKERFILE=Dockerfile.dev \
DOCKERFILE=$docker_file \
ROOT_DIR=$dir \
RELEASE_DATE=$build_date \
GIT_BRANCH=$branch \
SERVICE_DOCEDITOR=$doceditor \
SERVICE_LOGIN=$login \
SERVICE_CLIENT=$client \
APP_CORE_BASE_DOMAIN=$core_base_domain \
APP_URL_PORTAL="http://$local_ip:8092" \
ENV_EXTENSION=$env_extension \
docker compose -f docspace.dev.yml up -d

View File

@ -1,18 +1,21 @@
#!/bin/bash
rd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "Run script directory:" $dir
#rd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
#echo "Run script directory:" $dir
dir=$(builtin cd $rd/../../; pwd)
#dir=$(builtin cd $rd/../../; pwd)
echo "Root directory:" $dir
#echo "Root directory:" $dir
cd $dir/build/install/docker/
#cd $dir/build/install/docker/
docker_dir="$( pwd )"
#docker_dir="$( pwd )"
echo "Docker directory:" $docker_dir
#echo "Docker directory:" $docker_dir
echo "Stop all backend services"
DOCKERFILE=Dockerfile.dev \
docker compose -f docspace.dev.yml down
echo "Stop all backend containers"
# DOCKERFILE=Dockerfile.dev \
# docker compose -f docspace.dev.yml down
docker stop $(docker ps -a | egrep "onlyoffice" | egrep -v "mysql|rabbitmq|redis|elasticsearch|documentserver" | awk 'NR>0 {print $1}')
echo "Remove all backend containers"
docker rm -f $(docker ps -a | egrep "onlyoffice" | egrep -v "mysql|rabbitmq|redis|elasticsearch|documentserver" | awk 'NR>0 {print $1}')

View File

@ -137,7 +137,7 @@ public class LdapUserManager
try
{
_countManagerChecker.CheckUsed().Wait();
_countManagerChecker.CheckAppend().Wait();
}
catch (Exception)
{

View File

@ -238,7 +238,7 @@ public abstract class BaseStartup
}
}
private IEnumerable<Assembly> GetAutoMapperProfileAssemblies()
public static IEnumerable<Assembly> GetAutoMapperProfileAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies().Where(x => x.GetName().Name.StartsWith("ASC."));
}

View File

@ -25,18 +25,18 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Api.Core.Core;
internal static class QuotaExtension
public static class QuotaExtension
{
public static void RegisterFeature(this IServiceCollection services)
{
services.AddScoped<ITenantQuotaFeatureChecker, CountManagerChecker>();
services.AddScoped<TenantQuotaFeatureChecker<CountManagerFeature, int>, CountManagerChecker>();
services.AddScoped<TenantQuotaFeatureCheckerCount<CountManagerFeature>, CountManagerChecker>();
services.AddScoped<CountManagerChecker>();
services.AddScoped<ITenantQuotaFeatureStat<CountManagerFeature, int>, CountManagerStatistic>();
services.AddScoped<CountManagerStatistic>();
services.AddScoped<ITenantQuotaFeatureChecker, CountUserChecker>();
services.AddScoped<TenantQuotaFeatureChecker<CountUserFeature, int>, CountUserChecker>();
services.AddScoped<TenantQuotaFeatureCheckerCount<CountUserFeature>, CountUserChecker>();
services.AddScoped<CountUserChecker>();
services.AddScoped<ITenantQuotaFeatureStat<CountUserFeature, int>, CountUserStatistic>();
services.AddScoped<CountUserStatistic>();

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.Core.Billing;
namespace ASC.Api.Core.Middleware;
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
@ -39,7 +41,9 @@ public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
var withStackTrace = true;
switch (context.Exception)
var exception = context.Exception.GetBaseException();
switch (exception)
{
case ItemNotFoundException:
status = HttpStatusCode.NotFound;
@ -61,11 +65,12 @@ public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
status = HttpStatusCode.Forbidden;
break;
case TenantQuotaException:
case BillingNotFoundException:
status = HttpStatusCode.PaymentRequired;
break;
}
var result = new ObjectResult(new ErrorApiResponse(status, context.Exception, message, withStackTrace))
var result = new ObjectResult(new ErrorApiResponse(status, exception, message, withStackTrace))
{
StatusCode = (int)status
};

View File

@ -5,6 +5,8 @@
<TargetFramework>net6.0</TargetFramework>
<FileUpgradeFlags />
<UpgradeBackupLocation />
<AssemblyVersion>1.0.1</AssemblyVersion>
<InformationalVersion>1.0.1</InformationalVersion>
<AssemblyTitle>ASC.Core.Common</AssemblyTitle>
<Company>Ascensio System SIA</Company>
<Product>ASC.Core.Common</Product>

View File

@ -709,32 +709,45 @@ public class TariffService : ITariffService
using var dbContext = _dbContextFactory.CreateDbContext();
using var tx = dbContext.Database.BeginTransaction();
if (tariffInfo.DueDate.Equals(DateTime.MaxValue))
var stamp = tariffInfo.DueDate;
if (stamp.Equals(DateTime.MaxValue))
{
tariffInfo.DueDate = new DateTime(tariffInfo.DueDate.Year, tariffInfo.DueDate.Month, tariffInfo.DueDate.Day, tariffInfo.DueDate.Hour, tariffInfo.DueDate.Minute, tariffInfo.DueDate.Second);
stamp = stamp.Date.Add(new TimeSpan(tariffInfo.DueDate.Hour, tariffInfo.DueDate.Minute, tariffInfo.DueDate.Second));
}
var efTariff = new DbTariff
{
Id = tariffInfo.Id,
Tenant = tenant,
Stamp = tariffInfo.DueDate,
Stamp = stamp,
CustomerId = tariffInfo.CustomerId,
CreateOn = DateTime.UtcNow
};
if (efTariff.Id == default)
{
efTariff.Id = (-tenant);
}
if (efTariff.CustomerId == default)
{
efTariff.CustomerId = "";
}
efTariff = dbContext.AddOrUpdate(r => r.Tariffs, efTariff);
dbContext.SaveChanges();
var tariffRows = tariffInfo.Quotas.Select(q => new DbTariffRow
foreach (var q in tariffInfo.Quotas)
{
TariffId = efTariff.Id,
Quota = q.Id,
Quantity = q.Quantity,
Tenant = tenant
});
dbContext.AddOrUpdate(r => r.TariffRows, new DbTariffRow
{
TariffId = efTariff.Id,
Quota = q.Id,
Quantity = q.Quantity,
Tenant = tenant
});
}
dbContext.TariffRows.AddRange(tariffRows);
dbContext.SaveChanges();
inserted = true;
@ -792,7 +805,7 @@ public class TariffService : ITariffService
}
var delay = 0;
bool setDelay = true;
var setDelay = true;
if (_trialEnabled)
{
@ -831,12 +844,11 @@ public class TariffService : ITariffService
if (tariff.DueDate != DateTime.MinValue && tariff.DueDate.Date < DateTime.UtcNow.Date && delay > 0)
{
tariff.State = TariffState.Delay;
tariff.DelayDueDate = tariff.DueDate.Date.AddDays(delay);
}
if (tariff.DueDate == DateTime.MinValue ||
tariff.DueDate != DateTime.MaxValue && tariff.DueDate.Date.AddDays(delay) < DateTime.UtcNow.Date)
tariff.DueDate != DateTime.MaxValue && tariff.DueDate.Date < DateTime.UtcNow.Date.AddDays(-delay))
{
tariff.State = TariffState.NotPaid;
}

View File

@ -61,8 +61,8 @@ public class UserManager
private readonly CardDavAddressbook _cardDavAddressbook;
private readonly ILogger<UserManager> _log;
private readonly ICache _cache;
private readonly TenantQuotaFeatureChecker<CountManagerFeature, int> _tenantQuotaFeatureChecker;
private readonly TenantQuotaFeatureChecker<CountUserFeature, int> _activeUsersFeatureChecker;
private readonly TenantQuotaFeatureCheckerCount<CountManagerFeature> _tenantQuotaFeatureChecker;
private readonly TenantQuotaFeatureCheckerCount<CountUserFeature> _activeUsersFeatureChecker;
private readonly Constants _constants;
private Tenant _tenant;
@ -85,8 +85,8 @@ public class UserManager
CardDavAddressbook cardDavAddressbook,
ILogger<UserManager> log,
ICache cache,
TenantQuotaFeatureChecker<CountManagerFeature, int> tenantQuotaFeatureChecker,
TenantQuotaFeatureChecker<CountUserFeature, int> activeUsersFeatureChecker
TenantQuotaFeatureCheckerCount<CountManagerFeature> tenantQuotaFeatureChecker,
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker
)
{
_userService = service;
@ -117,8 +117,8 @@ public class UserManager
CardDavAddressbook cardDavAddressbook,
ILogger<UserManager> log,
ICache cache,
TenantQuotaFeatureChecker<CountManagerFeature, int> tenantQuotaFeatureChecker,
TenantQuotaFeatureChecker<CountUserFeature, int> activeUsersFeatureChecker,
TenantQuotaFeatureCheckerCount<CountManagerFeature> tenantQuotaFeatureChecker,
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
IHttpContextAccessor httpContextAccessor)
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache, tenantQuotaFeatureChecker, activeUsersFeatureChecker)
{
@ -334,18 +334,6 @@ public class UserManager
{
throw new TenantQuotaException("Maximum number of users exceeded");
}
if (u.Status == EmployeeStatus.Active)
{
if (isVisitor)
{
_activeUsersFeatureChecker.CheckUsed().Wait();
}
else
{
_tenantQuotaFeatureChecker.CheckUsed().Wait();
}
}
}
if (u.Status == EmployeeStatus.Terminated && u.Id == _tenantManager.GetCurrentTenant().OwnerId)
@ -354,6 +342,19 @@ public class UserManager
}
var oldUserData = _userService.GetUserByUserName(_tenantManager.GetCurrentTenant().Id, u.UserName);
if (Equals(oldUserData, Constants.LostUser))
{
if (isVisitor)
{
_activeUsersFeatureChecker.CheckAppend().Wait();
}
else
{
_tenantQuotaFeatureChecker.CheckAppend().Wait();
}
}
var newUser = _userService.SaveUser(_tenantManager.GetCurrentTenant().Id, u);
if (syncCardDav)

View File

@ -218,7 +218,7 @@ public class DbTenantService : ITenantService
tenant.LastModified = DateTime.UtcNow;
var dbTenant = _mapper.Map<Tenant, DbTenant>(tenant);
dbTenant.Id = 0;
dbTenant = tenantDbContext.Tenants.Add(dbTenant).Entity;
tenantDbContext.SaveChanges();
tenant.Id = dbTenant.Id;
@ -235,7 +235,7 @@ public class DbTenantService : ITenantService
dbTenant.MappedDomain = !string.IsNullOrEmpty(tenant.MappedDomain) ? tenant.MappedDomain.ToLowerInvariant() : null;
dbTenant.Version = tenant.Version;
dbTenant.VersionChanged = tenant.VersionChanged;
dbTenant.Name = tenant.Name ?? tenant.Alias;
dbTenant.Name = tenant.Name ?? "";
dbTenant.Language = tenant.Language;
dbTenant.TimeZone = tenant.TimeZone;
dbTenant.TrustedDomainsRaw = tenant.GetTrustedDomains();
@ -405,11 +405,11 @@ public class DbTenantService : ITenantService
}
}
var existsTenants = tenantDbContext.TenantForbiden.Where(r => r.Address.StartsWith(domain)).Select(r => r.Address)
.Union(tenantDbContext.Tenants.Where(r => r.Alias.StartsWith(domain) && r.Id != tenantId).Select(r => r.Alias))
.Union(tenantDbContext.Tenants.Where(r => r.MappedDomain.StartsWith(domain) && r.Id != tenantId && r.Status != TenantStatus.RemovePending).Select(r => r.MappedDomain));
var existsTenants = tenantDbContext.TenantForbiden.Where(r => r.Address.StartsWith(domain)).Select(r => r.Address).ToList();
existsTenants.AddRange(tenantDbContext.Tenants.Where(r => r.Alias.StartsWith(domain) && r.Id != tenantId).Select(r => r.Alias).ToList());
existsTenants.AddRange(tenantDbContext.Tenants.Where(r => r.MappedDomain.StartsWith(domain) && r.Id != tenantId && r.Status != TenantStatus.RemovePending).Select(r => r.MappedDomain).ToList());
throw new TenantAlreadyExistsException("Address busy.", existsTenants);
throw new TenantAlreadyExistsException("Address busy.", existsTenants.Distinct());
}
}

View File

@ -79,7 +79,7 @@ public static class DbQuotaExtension
Tenant = -3,
Name = "startup",
Description = null,
Features = "free,audit,ldap,sso,restore,total_size:2147483648,file_size:100,manager:1,rooms:12,usersInRoom:3",
Features = "free,total_size:2147483648,manager:1,room:12,usersInRoom:3",
Price = 0,
ProductId = null,
Visible = false

View File

@ -69,7 +69,7 @@ public class DbTenant : IMapFrom<Tenant>
.ForMember(dest => dest.TrustedDomainsRaw, opt => opt.MapFrom(dest => dest.GetTrustedDomains()))
.ForMember(dest => dest.Alias, opt => opt.MapFrom(dest => dest.Alias.ToLowerInvariant()))
.ForMember(dest => dest.LastModified, opt => opt.MapFrom(dest => DateTime.UtcNow))
.ForMember(dest => dest.Name, opt => opt.MapFrom(dest => dest.Name ?? dest.Alias))
.ForMember(dest => dest.Name, opt => opt.MapFrom(dest => dest.Name ?? ""))
.ForMember(dest => dest.MappedDomain, opt => opt.MapFrom(dest =>
!string.IsNullOrEmpty(dest.MappedDomain) ? dest.MappedDomain.ToLowerInvariant() : null));
}

View File

@ -42,9 +42,33 @@ public class HostedSolution
internal DbSettingsManager SettingsManager { get; set; }
internal CoreSettings CoreSettings { get; set; }
public string Region { get; set; }
public string Region { get; private set; }
public HostedSolution() { }
public HostedSolution(ITenantService tenantService,
IUserService userService,
IQuotaService quotaService,
ITariffService tariffService,
UserFormatter userFormatter,
TenantManager clientTenantManager,
TenantUtil tenantUtil,
DbSettingsManager settingsManager,
CoreSettings coreSettings)
{
TenantService = tenantService;
UserService = userService;
QuotaService = quotaService;
TariffService = tariffService;
UserFormatter = userFormatter;
ClientTenantManager = clientTenantManager;
TenantUtil = tenantUtil;
SettingsManager = settingsManager;
CoreSettings = coreSettings;
}
public void Init(string region)
{
Region = region;
}
public List<Tenant> GetTenants(DateTime from)
{
@ -146,8 +170,6 @@ public class HostedSolution
// save tenant owner
tenant.OwnerId = user.Id;
tenant = TenantService.SaveTenant(CoreSettings, tenant);
SettingsManager.SaveSettings(new TenantControlPanelSettings { LimitedAccess = registrationInfo.LimitedControlPanel }, tenant.Id);
}
public Tenant SaveTenant(Tenant tenant)

View File

@ -45,14 +45,7 @@ public abstract class TenantQuotaFeatureChecker<T, T1> : ITenantQuotaFeatureChec
_tenantManager = tenantManager;
}
public async Task CheckUsed()
{
var quota = _tenantManager.GetCurrentTenantQuota();
var used = await _tenantQuotaFeatureStatistic.GetValue();
Check(quota, used);
}
public async Task CheckUsed(TenantQuota quota)
public virtual async Task CheckUsed(TenantQuota quota)
{
var used = await _tenantQuotaFeatureStatistic.GetValue();
Check(quota, used);
@ -78,4 +71,16 @@ public abstract class TenantQuotaFeatureChecker<T, T1> : ITenantQuotaFeatureChec
throw new TenantQuotaException(string.Format(Exception, val));
}
}
}
public abstract class TenantQuotaFeatureCheckerCount<T> : TenantQuotaFeatureChecker<T, int> where T : TenantQuotaFeature<int>
{
protected TenantQuotaFeatureCheckerCount(ITenantQuotaFeatureStat<T, int> tenantQuotaFeatureStatistic, TenantManager tenantManager) : base(tenantQuotaFeatureStatistic, tenantManager)
{
}
public async Task CheckAppend()
{
CheckAdd((await _tenantQuotaFeatureStatistic.GetValue()) + 1);
}
}

View File

@ -44,7 +44,6 @@ public class TenantRegistrationInfo
public bool Spam { get; set; }
public bool Calls { get; set; }
public string Campaign { get; set; }
public bool LimitedControlPanel { get; set; }
public TenantRegistrationInfo()
{

View File

@ -48,7 +48,7 @@ public class Tests
{
get
{
return Path.GetFullPath("..\\..\\..\\..\\..\\..\\");
return Path.GetFullPath(Utils.ConvertPathToOS("../../../../../../"));
}
}
@ -58,10 +58,12 @@ public class Tests
public List<ModuleFolder> ModuleFolders { get; set; }
public List<KeyValuePair<string, string>> NotTranslatedToasts { get; set; }
public List<LanguageItem> CommonTranslations { get; set; }
public List<ParseJsonError> ParseJsonErrors { get; set; }
//public List<JsonEncodingError> WrongEncodingJsonErrors { get; set; }
private static readonly string _md5ExcludesPath = "../../../md5-excludes.json";
public List<ParseJsonError> ParseJsonErrors { get; set; }
public static string ConvertPathToOS { get; private set; }
//public List<JsonEncodingError> WrongEncodingJsonErrors { get; set; }
private static readonly string _md5ExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../md5-excludes.json"));
//private static string _encodingExcludesPath = "../../../encoding-excludes.json";
@ -81,26 +83,28 @@ public class Tests
var moduleWorkspaces = new List<string>
{
"packages\\client",
"packages\\common",
"packages\\components",
"packages\\editor",
"packages\\login"
Utils.ConvertPathToOS("packages/client"),
Utils.ConvertPathToOS("packages/common"),
Utils.ConvertPathToOS("packages/components"),
Utils.ConvertPathToOS("packages/editor"),
Utils.ConvertPathToOS("packages/login")
};
Workspaces = new List<string>();
Workspaces.AddRange(moduleWorkspaces);
Workspaces.Add("public\\locales");
Workspaces.Add(Utils.ConvertPathToOS("public/locales"));
var translationFiles = from wsPath in Workspaces
let clientDir = Path.Combine(BasePath, wsPath)
from filePath in Directory.EnumerateFiles(clientDir, "*.json", SearchOption.AllDirectories)
where filePath.Contains("public\\locales\\")
where filePath.Contains(Utils.ConvertPathToOS("public/locales/"))
select Path.GetFullPath(filePath);
TestContext.Progress.WriteLine($"Base path = {BasePath}");
TestContext.Progress.WriteLine($"Found translationFiles by *.json filter = {translationFiles.Count()}. First path is '{translationFiles.FirstOrDefault()}'");
TranslationFiles = new List<TranslationFile>();
foreach (var path in translationFiles)
@ -154,22 +158,26 @@ public class Tests
catch (Exception ex)
{
ParseJsonErrors.Add(new ParseJsonError(path, ex));
Debug.WriteLine($"File path = {path} failed to parse with error: {ex.Message}");
TestContext.Progress.WriteLine($"File path = {path} failed to parse with error: {ex.Message}");
}
}
TestContext.Progress.WriteLine($"Found TranslationFiles = {TranslationFiles.Count()}. First path is '{TranslationFiles.FirstOrDefault()?.FilePath}'");
var javascriptFiles = (from wsPath in Workspaces
let clientDir = Path.Combine(BasePath, wsPath)
from file in Directory.EnumerateFiles(clientDir, "*.js", SearchOption.AllDirectories)
where !file.Contains("dist\\")
select file)
from filePath in Directory.EnumerateFiles(clientDir, "*.js", SearchOption.AllDirectories)
where !filePath.Contains(Utils.ConvertPathToOS("dist/")) && !filePath.Contains(".test.js") && !filePath.Contains(".stories.js")
select Utils.ConvertPathToOS(filePath))
.ToList();
javascriptFiles.AddRange(from wsPath in Workspaces
let clientDir = Path.Combine(BasePath, wsPath)
from file in Directory.EnumerateFiles(clientDir, "*.jsx", SearchOption.AllDirectories)
where !file.Contains("dist\\")
select file);
from filePath in Directory.EnumerateFiles(clientDir, "*.jsx", SearchOption.AllDirectories)
where !filePath.Contains(Utils.ConvertPathToOS("dist/")) && !filePath.Contains(".test.jsx") && !filePath.Contains(".stories.jsx")
select Utils.ConvertPathToOS(filePath));
TestContext.Progress.WriteLine($"Found javascriptFiles by *.js(x) filter = {javascriptFiles.Count()}. First path is '{javascriptFiles.FirstOrDefault()}'");
JavaScriptFiles = new List<JavaScriptFile>();
@ -222,6 +230,8 @@ public class Tests
JavaScriptFiles.Add(jsFile);
}
TestContext.Progress.WriteLine($"Found JavaScriptFiles = {JavaScriptFiles.Count()}. First path is '{JavaScriptFiles.FirstOrDefault()?.Path}'");
ModuleFolders = new List<ModuleFolder>();
var list = TranslationFiles
@ -246,6 +256,8 @@ public class Tests
})
.ToList();
TestContext.Progress.WriteLine($"Found moduleTranslations = {moduleTranslations.Count()}. First path is '{moduleTranslations.FirstOrDefault()?.ModulePath}'");
var moduleJsTranslatedFiles = JavaScriptFiles
.Select(t => new
{
@ -261,6 +273,8 @@ public class Tests
})
.ToList();
TestContext.Progress.WriteLine($"Found moduleJsTranslatedFiles = {moduleJsTranslatedFiles.Count()}. First path is '{moduleJsTranslatedFiles.FirstOrDefault()?.ModulePath}'");
foreach (var wsPath in moduleWorkspaces)
{
var t = moduleTranslations.FirstOrDefault(t => t.ModulePath == wsPath);
@ -277,14 +291,21 @@ public class Tests
});
}
TestContext.Progress.WriteLine($"Found ModuleFolders = {ModuleFolders.Count()}. First path is '{ModuleFolders.FirstOrDefault()?.Path}'");
CommonTranslations = TranslationFiles
.Where(file => file.FilePath.StartsWith($"{BasePath}public\\locales"))
.Where(file => file.FilePath.StartsWith(Utils.ConvertPathToOS($"{BasePath}public/locales")))
.Select(t => new LanguageItem
{
Path = t.FilePath,
Language = t.Language,
Translations = t.Translations
}).ToList();
TestContext.Progress.WriteLine($"Found CommonTranslations = {CommonTranslations.Count()}. First path is '{CommonTranslations.FirstOrDefault()?.Path}'");
TestContext.Progress.WriteLine($"Found _md5Excludes = {_md5Excludes.Count()} Path to file '{_md5ExcludesPath}'");
}
[Test]
@ -296,8 +317,8 @@ public class Tests
public static Tuple<string, string> getPaths(string language)
{
const string dictionariesPath = @"..\..\..\dictionaries";
const string additionalPath = @"..\..\..\additional";
const string dictionariesPath = @"../../../dictionaries";
const string additionalPath = @"../../../additional";
var path = dictionariesPath;
@ -310,8 +331,8 @@ public class Tests
break;
}
var dicPath = Path.Combine(path, language, $"{language}.dic");
var affPath = Path.Combine(path, language, $"{language}.aff");
var dicPath = Utils.ConvertPathToOS(Path.Combine(path, language, $"{language}.dic"));
var affPath = Utils.ConvertPathToOS(Path.Combine(path, language, $"{language}.aff"));
return new Tuple<string, string>(dicPath, affPath);
}
@ -407,6 +428,7 @@ public class Tests
public void DublicatesFilesByMD5HashTest()
{
var duplicatesByMD5 = TranslationFiles
.Where(t => t.Language != "pt-BR")
.Where(t => !_md5Excludes.Contains(t.Md5Hash))
.GroupBy(t => t.Md5Hash)
.Where(grp => grp.Count() > 1)
@ -553,7 +575,7 @@ public class Tests
var lngFilePaths = lng.Files.Select(f => f.FilePath).ToList();
var notFoundFilePaths = enFilePaths
.Select(p => p.Replace("\\en\\", $"\\{lng.Lng}\\"))
.Select(p => p.Replace(Utils.ConvertPathToOS("/en/"), Utils.ConvertPathToOS($"/{lng.Lng}/")))
.Where(p => !lngFilePaths.Contains(p));
message += string.Join("\r\n", notFoundFilePaths);
@ -562,7 +584,7 @@ public class Tests
/*foreach (var path in notFoundFilePaths)
{
SaveNotFoundLanguage(path.Replace($"\\{lng.Lng}\\", "\\en\\"), path);
SaveNotFoundLanguage(path.Replace(Utils.ConvertPathToOS($"\\{lng.Lng}\\"), Utils.ConvertPathToOS("\\en\\")), path);
}*/
}
}
@ -613,7 +635,7 @@ public class Tests
{
var lngKeys = lng.Translations.Select(f => f.Key).ToList();
var enKeys = enLanguages.Where(l => l.Path == lng.Path.Replace($"\\{lng.Language}\\", "\\en\\"))
var enKeys = enLanguages.Where(l => l.Path == lng.Path.Replace(Utils.ConvertPathToOS($"/{lng.Language}/"), Utils.ConvertPathToOS("/en/")))
.SelectMany(l => l.Translations.Select(f => f.Key))
.ToList();
@ -698,7 +720,7 @@ public class Tests
if (module.AppliedJsTranslationKeys == null && module.AvailableLanguages != null)
{
message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' NOT USES";
message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' NOT USED\r\n";
var list = module.AvailableLanguages
.SelectMany(l => l.Translations.Select(t => t.Key).ToList())
@ -857,15 +879,13 @@ public class Tests
switch (folderName)
{
case "Client":
return Workspaces.Find(w => w.Contains("ASC.Web.Client"));
case "Files":
return Workspaces.Find(w => w.Contains("ASC.Files"));
return Workspaces.Find(w => w.Contains("client"));
case "Editor":
return Workspaces.Find(w => w.Contains("editor"));
case "Login":
return Workspaces.Find(w => w.Contains("ASC.Web.Login"));
case "People":
return Workspaces.Find(w => w.Contains("ASC.People"));
return Workspaces.Find(w => w.Contains("login"));
default:
return Path.Combine(BasePath, "public\\locales");
return Path.Combine(BasePath, Utils.ConvertPathToOS("public\\locales"));
}
}
@ -1144,14 +1164,14 @@ public class Tests
/// <summary>
/// Converts a file from one encoding to another.
/// </summary>
/// <param name=”sourcePath”>the file to convert</param>
/// <param name=”destPath”>the destination for the converted file</param>
/// <param name=”sourceEncoding”>the original file encoding</param>
/// <param name=”destEncoding”>the encoding to which the contents should be converted</param>
/// <param name="sourcePath">the file to convert</param>
/// <param name="destPath">the destination for the converted file</param>
/// <param name="sourceEncoding">the original file encoding</param>
/// <param name="destEncoding">the encoding to which the contents should be converted</param>
//public static void ConvertFileEncoding(string sourcePath, string destPath,
// Encoding sourceEncoding, Encoding destEncoding)
//{
// // If the destinations parent doesnt exist, create it.
// // If the destination's parent doesn't exist, create it.
// var parent = Path.GetDirectoryName(Path.GetFullPath(destPath));
// if (!Directory.Exists(parent))
// {

View File

@ -32,7 +32,7 @@ public class JavaScriptFile
{
public JavaScriptFile(string path)
{
Path = path.Replace("/", "\\");
Path = Utils.ConvertPathToOS(path);
}
public string Path { get; }

View File

@ -35,17 +35,17 @@ namespace Frontend.Translations.Tests.Models;
public class SpellCheckResult
{
private static Regex wordRegex = new Regex(@"[\p{L}-]+", RegexOptions.Multiline | RegexOptions.Compiled);
private static Regex regVariables = new Regex("\\{\\{([^\\{].?[^\\}]+)\\}\\}", RegexOptions.Compiled | RegexOptions.Multiline);
private static Regex htmlTags = new Regex("<[^>]*>", RegexOptions.Compiled | RegexOptions.Multiline);
private static List<string> trademarks = new List<string>()
private static readonly Regex wordRegex = new Regex(@"[\p{L}-]+", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex regVariables = new Regex("\\{\\{([^\\{].?[^\\}]+)\\}\\}", RegexOptions.Compiled | RegexOptions.Multiline);
private static readonly Regex htmlTags = new Regex("<[^>]*>", RegexOptions.Compiled | RegexOptions.Multiline);
private static readonly List<string> trademarks = new List<string>()
{
"onlyoffice.com", "onlyoffice.eu", "Office Open XML", "ONLYOFFICE Desktop Editors",
"ONLYOFFICE Desktop", "ONLYOFFICE Documents", "Google Drive", "Twitter", "Facebook", "LinkedIn", "Google",
"Yandex", "Yandex.Disk", "Dropbox","OneDrive","ONLYOFFICE", "DocuSign", "e-mail",
"SharePoint", "Windows Phone", "Enterprise Edition", "AES-256"
};
private static List<string> exclusions = new List<string>()
private static readonly List<string> exclusions = new List<string>()
{
"ok","doc","docx","xls","xlsx","ppt","pptx","xml","ooxml","jpg","png","mb","ip",
"canvas","tag","Disk","Box","Dcs","zip","Android","Authenticator","iOS","Windows",
@ -53,7 +53,7 @@ public class SpellCheckResult
"Portal","Favicon","URL","QR", "email", "app", "api"
};
private static List<SpellCheckExclude> excludes = File.Exists("../../../spellcheck-excludes.json")
private static readonly List<SpellCheckExclude> excludes = File.Exists("../../../spellcheck-excludes.json")
? JsonConvert.DeserializeObject<List<SpellCheckExclude>>(File.ReadAllText("../../../spellcheck-excludes.json"))
: new List<SpellCheckExclude>();

View File

@ -33,7 +33,7 @@ public class TranslationFile
{
public TranslationFile(string path, List<TranslationItem> translations, string md5hash = null)
{
FilePath = path.Replace("/", "\\");
FilePath = Utils.ConvertPathToOS(path);
FileName = Path.GetFileName(FilePath);

View File

@ -56,8 +56,8 @@ public static class SpellCheck
public static DicPaths GetDictionaryPaths(string lng)
{
const string dictionariesPath = @"..\..\..\dictionaries";
const string additionalPath = @"..\..\..\additional";
const string dictionariesPath = @"../../../dictionaries";
const string additionalPath = @"../../../additional";
var path = dictionariesPath;
string language;

View File

@ -0,0 +1,14 @@
using System;
using System.IO;
namespace Frontend.Translations.Tests
{
public static class Utils
{
public static string ConvertPathToOS(string path)
{
return Path.DirectorySeparatorChar == '/' ? path.Replace("\\", "/") : path.Replace("/", "\\");
}
}
}

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Classes;
public class AllowCrossSiteJsonAttribute : System.Web.Http.Filters.ActionFilterAttribute

View File

@ -24,12 +24,17 @@
// 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.ApiSystem.Classes;
[Scope]
public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
{
private readonly ILogger<AuthHandler> _log;
private readonly IConfiguration _configuration;
private readonly ApiSystemHelper _apiSystemHelper;
private readonly MachinePseudoKeys _machinePseudoKeys;
private readonly IHttpContextAccessor _httpContextAccessor;
public AuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) :
base(options, logger, encoder, clock)
{
@ -47,29 +52,21 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
IHttpContextAccessor httpContextAccessor) :
base(options, logger, encoder, clock)
{
Configuration = configuration;
_configuration = configuration;
Log = log;
_log = log;
ApiSystemHelper = apiSystemHelper;
MachinePseudoKeys = machinePseudoKeys;
HttpContextAccessor = httpContextAccessor;
}
private ILogger<AuthHandler> Log { get; }
private IConfiguration Configuration { get; }
private ApiSystemHelper ApiSystemHelper { get; }
private MachinePseudoKeys MachinePseudoKeys { get; }
private IHttpContextAccessor HttpContextAccessor { get; }
_apiSystemHelper = apiSystemHelper;
_machinePseudoKeys = machinePseudoKeys;
_httpContextAccessor = httpContextAccessor;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (Convert.ToBoolean(Configuration[Scheme.Name] ?? "false"))
if (Convert.ToBoolean(_configuration[Scheme.Name] ?? "false"))
{
Log.LogDebug("Auth for {0} skipped", Scheme.Name);
_log.LogDebug("Auth for {0} skipped", Scheme.Name);
Authenticate();
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)));
}
@ -81,7 +78,7 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
if (string.IsNullOrEmpty(header))
{
Log.LogDebug("Auth header is NULL");
_log.LogDebug("Auth header is NULL");
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Unauthorized))));
}
@ -94,8 +91,8 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
if (splitted.Length < 3)
{
Log.LogDebug("Auth failed: invalid token {0}.", header);
_log.LogDebug("Auth failed: invalid token {0}.", header);
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Unauthorized))));
}
@ -103,51 +100,67 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
var date = splitted[1];
var orighash = splitted[2];
Log.LogDebug("Variant of correct auth:" + ApiSystemHelper.CreateAuthToken(pkey));
_log.LogDebug("Variant of correct auth:" + _apiSystemHelper.CreateAuthToken(pkey));
if (!string.IsNullOrWhiteSpace(date))
{
var timestamp = DateTime.ParseExact(date, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
var trustInterval = TimeSpan.FromMinutes(Convert.ToDouble(Configuration["auth:trust-interval"] ?? "5"));
var trustInterval = TimeSpan.FromMinutes(Convert.ToDouble(_configuration["auth:trust-interval"] ?? "5"));
if (DateTime.UtcNow > timestamp.Add(trustInterval))
{
Log.LogDebug("Auth failed: invalid timesatmp {0}, now {1}.", timestamp, DateTime.UtcNow);
_log.LogDebug("Auth failed: invalid timesatmp {0}, now {1}.", timestamp, DateTime.UtcNow);
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Forbidden))));
}
}
var skey = MachinePseudoKeys.GetMachineConstant();
var skey = _machinePseudoKeys.GetMachineConstant();
using var hasher = new HMACSHA1(skey);
var data = string.Join("\n", date, pkey);
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
{
Log.LogDebug("Auth failed: invalid token {0}, expect {1} or {2}.", orighash, WebEncoders.Base64UrlEncode(hash), Convert.ToBase64String(hash));
_log.LogDebug("Auth failed: invalid token {0}, expect {1} or {2}.", orighash, WebEncoders.Base64UrlEncode(hash), Convert.ToBase64String(hash));
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Forbidden))));
}
}
else
{
Log.LogDebug("Auth failed: invalid auth header. Sheme: {0}, parameter: {1}.", Scheme.Name, header);
_log.LogDebug("Auth failed: invalid auth header. Sheme: {0}, parameter: {1}.", Scheme.Name, header);
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Forbidden))));
}
}
catch (Exception ex)
{
Log.LogError(ex, "auth error");
_log.LogError(ex, "auth error");
return Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.InternalServerError))));
}
var identity = new ClaimsIdentity(Scheme.Name);
Log.LogInformation("Auth success {0}", Scheme.Name);
if (HttpContextAccessor?.HttpContext != null) HttpContextAccessor.HttpContext.User = new CustomClaimsPrincipal(new ClaimsIdentity(Scheme.Name), identity);
_log.LogInformation("Auth success {0}", Scheme.Name);
if (_httpContextAccessor?.HttpContext != null) _httpContextAccessor.HttpContext.User = new CustomClaimsPrincipal(new ClaimsIdentity(Scheme.Name), identity);
Authenticate();
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)));
}
private void Authenticate()
{
var account = Core.Configuration.Constants.SystemAccounts.FirstOrDefault(a => a.ID == Core.Configuration.Constants.CoreSystem.ID);
var claims = new List<Claim>
{
new Claim(ClaimTypes.Sid, account.ID.ToString()),
new Claim(ClaimTypes.Name, account.Name),
new Claim(ClaimTypes.Role, Role.System)
};
_httpContextAccessor.HttpContext.User = new CustomClaimsPrincipal(new ClaimsIdentity(account, claims), account);
}
}

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Classes;
[Singletone]

View File

@ -24,64 +24,24 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.ApiSystem.Controllers;
[Scope]
public class CommonMethods
{
private IHttpContextAccessor HttpContextAccessor { get; }
private IConfiguration Configuration { get; }
private ILogger<CommonMethods> Log { get; }
private CoreSettings CoreSettings { get; }
private CommonLinkUtility CommonLinkUtility { get; }
private EmailValidationKeyProvider EmailValidationKeyProvider { get; }
private TimeZoneConverter TimeZoneConverter { get; }
private CommonConstants CommonConstants { get; }
private HostedSolution HostedSolution { get; }
private IMemoryCache MemoryCache { get; }
private CoreBaseSettings CoreBaseSettings { get; }
private TenantManager TenantManager { get; }
private IHttpClientFactory ClientFactory { get; }
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IConfiguration _configuration;
private readonly ILogger<CommonMethods> _log;
private readonly CoreSettings _coreSettings;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly EmailValidationKeyProvider _emailValidationKeyProvider;
private readonly TimeZoneConverter _timeZoneConverter;
private readonly CommonConstants _commonConstants;
private readonly HostedSolution _hostedSolution;
private readonly IMemoryCache _memoryCache;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly TenantManager _tenantManager;
private readonly IHttpClientFactory _clientFactory;
public CommonMethods(
IHttpContextAccessor httpContextAccessor,
@ -92,98 +52,88 @@ public class CommonMethods
EmailValidationKeyProvider emailValidationKeyProvider,
TimeZoneConverter timeZoneConverter, CommonConstants commonConstants,
IMemoryCache memoryCache,
IOptionsSnapshot<HostedSolution> hostedSolutionOptions,
HostedSolution hostedSolution,
CoreBaseSettings coreBaseSettings,
TenantManager tenantManager,
IHttpClientFactory clientFactory)
{
HttpContextAccessor = httpContextAccessor;
Configuration = configuration;
Log = log;
CoreSettings = coreSettings;
CommonLinkUtility = commonLinkUtility;
EmailValidationKeyProvider = emailValidationKeyProvider;
TimeZoneConverter = timeZoneConverter;
CommonConstants = commonConstants;
MemoryCache = memoryCache;
CoreBaseSettings = coreBaseSettings;
TenantManager = tenantManager;
ClientFactory = clientFactory;
HostedSolution = hostedSolutionOptions.Get(CommonConstants.BaseDbConnKeyString);
}
_httpContextAccessor = httpContextAccessor;
_configuration = configuration;
_log = log;
_coreSettings = coreSettings;
_commonLinkUtility = commonLinkUtility;
_emailValidationKeyProvider = emailValidationKeyProvider;
_timeZoneConverter = timeZoneConverter;
_commonConstants = commonConstants;
_memoryCache = memoryCache;
_coreBaseSettings = coreBaseSettings;
_tenantManager = tenantManager;
_clientFactory = clientFactory;
_hostedSolution = hostedSolution;
_hostedSolution.Init(CommonConstants.BaseDbConnKeyString);
}
public object ToTenantWrapper(Tenant t)
{
return new
{
created = t.CreationDateTime,
domain = t.GetTenantDomain(CoreSettings),
domain = t.GetTenantDomain(_coreSettings),
hostedRegion = t.HostedRegion,
industry = t.Industry,
language = t.Language,
name = t.Name,
name = t.Name == "" ? Resource.PortalName : t.Name,
ownerId = t.OwnerId,
partnerId = t.PartnerId,
paymentId = t.PaymentId,
portalName = t.Alias,
status = t.Status.ToString(),
tenantId = t.Id,
timeZoneName = TimeZoneConverter.GetTimeZone(t.TimeZone).DisplayName,
timeZoneName = _timeZoneConverter.GetTimeZone(t.TimeZone).DisplayName,
};
}
}
public string CreateReference(string requestUriScheme, string tenantDomain, string email, bool first = false, string module = "", bool sms = false)
{
var url = CommonLinkUtility.GetConfirmationUrlRelative(email, ConfirmType.Auth, (first ? "true" : "") + module + (sms ? "true" : ""));
var url = _commonLinkUtility.GetConfirmationUrlRelative(email, ConfirmType.Auth, (first ? "true" : "") + module + (sms ? "true" : ""));
return $"{requestUriScheme}{Uri.SchemeDelimiter}{tenantDomain}/{url}{(first ? "&first=true" : "")}{(string.IsNullOrEmpty(module) ? "" : "&module=" + module)}{(sms ? "&sms=true" : "")}";
}
public bool SendCongratulations(string requestUriScheme, Tenant tenant, bool skipWelcome, out string url)
{
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.Id, tenant.OwnerId.ToString() + ConfirmType.Auth);
var validationKey = _emailValidationKeyProvider.GetEmailKey(tenant.Id, tenant.OwnerId.ToString() + ConfirmType.Auth);
url = string.Format("{0}{1}{2}{3}{4}?userid={5}&key={6}",
requestUriScheme,
Uri.SchemeDelimiter,
tenant.GetTenantDomain(CoreSettings),
CommonConstants.WebApiBaseUrl,
tenant.GetTenantDomain(_coreSettings),
_commonConstants.WebApiBaseUrl,
"portal/sendcongratulations",
tenant.OwnerId,
validationKey);
if (skipWelcome)
{
Log.LogDebug("congratulations skiped");
_log.LogDebug("congratulations skiped");
return false;
}
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(url)
};
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/x-www-form-urlencoded"));
try
{
var httpClient = ClientFactory.CreateClient();
var httpClient = _clientFactory.CreateClient();
using var response = httpClient.Send(request);
using var stream = response.Content.ReadAsStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
var result = reader.ReadToEnd();
Log.LogDebug("congratulations result = {0}", result);
_log.LogDebug("congratulations result = {0}", result);
var resObj = JObject.Parse(result);
@ -194,7 +144,7 @@ public class CommonMethods
}
catch (Exception ex)
{
Log.LogError(ex, "SendCongratulations error");
_log.LogError(ex, "SendCongratulations error");
return false;
}
@ -204,21 +154,21 @@ public class CommonMethods
public bool GetTenant(IModel model, out Tenant tenant)
{
if (CoreBaseSettings.Standalone && model != null && !string.IsNullOrWhiteSpace((model.PortalName ?? "")))
if (_coreBaseSettings.Standalone && model != null && !string.IsNullOrWhiteSpace((model.PortalName ?? "")))
{
tenant = TenantManager.GetTenant((model.PortalName ?? "").Trim());
tenant = _tenantManager.GetTenant((model.PortalName ?? "").Trim());
return true;
}
if (model != null && model.TenantId.HasValue)
{
tenant = HostedSolution.GetTenant(model.TenantId.Value);
tenant = _hostedSolution.GetTenant(model.TenantId.Value);
return true;
}
if (model != null && !string.IsNullOrWhiteSpace((model.PortalName ?? "")))
{
tenant = HostedSolution.GetTenant((model.PortalName ?? "").Trim());
tenant = _hostedSolution.GetTenant((model.PortalName ?? "").Trim());
return true;
}
@ -230,29 +180,34 @@ public class CommonMethods
{
//the point is not needed in gmail.com
email = Regex.Replace(email ?? "", "\\.*(?=\\S*(@gmail.com$))", "").ToLower();
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(CommonConstants.AutotestSecretEmails))
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(_commonConstants.AutotestSecretEmails))
{
return false;
}
var regex = new Regex(CommonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
var regex = new Regex(_commonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
return regex.IsMatch(email);
}
public bool CheckMuchRegistration(TenantModel model, string clientIP, Stopwatch sw)
{
if (IsTestEmail(model.Email)) return false;
Log.LogDebug("clientIP = {0}", clientIP);
if (IsTestEmail(model.Email))
{
return false;
}
_log.LogDebug("clientIP = {0}", clientIP);
var cacheKey = "ip_" + clientIP;
if (MemoryCache.TryGetValue(cacheKey, out int ipAttemptsCount))
if (_memoryCache.TryGetValue(cacheKey, out int ipAttemptsCount))
{
MemoryCache.Remove(cacheKey);
_memoryCache.Remove(cacheKey);
}
ipAttemptsCount++;
MemoryCache.Set(
_memoryCache.Set(
// String that represents the name of the cache item,
// could be any string
cacheKey,
@ -265,14 +220,17 @@ public class CommonMethods
// Cache will expire after one hour
// You can change this time interval according
// to your requriements
SlidingExpiration = CommonConstants.MaxAttemptsTimeInterval,
SlidingExpiration = _commonConstants.MaxAttemptsTimeInterval,
// Cache will not be removed before expired
Priority = CacheItemPriority.NeverRemove
});
if (ipAttemptsCount <= CommonConstants.MaxAttemptsCount) return false;
Log.LogDebug("PortalName = {0}; Too much reqests from ip: {1}", model.PortalName, clientIP);
if (ipAttemptsCount <= _commonConstants.MaxAttemptsCount)
{
return false;
}
_log.LogDebug("PortalName = {0}; Too much reqests from ip: {1}", model.PortalName, clientIP);
sw.Stop();
return true;
@ -280,7 +238,7 @@ public class CommonMethods
public string GetClientIp()
{
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
return _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
//TODO: check old version
@ -306,25 +264,27 @@ public class CommonMethods
switch (recaptchaType)
{
case RecaptchaType.AndroidV2:
privateKey = Configuration["recaptcha:private-key:android"];
privateKey = _configuration["recaptcha:private-key:android"];
break;
case RecaptchaType.iOSV2:
privateKey = Configuration["recaptcha:private-key:ios"];
privateKey = _configuration["recaptcha:private-key:ios"];
break;
default:
privateKey = Configuration["recaptcha:private-key"];
privateKey = _configuration["recaptcha:private-key:default"];
break;
}
var data = $"secret={privateKey}&remoteip={ip}&response={response}";
var url = Configuration["recaptcha:verify-url"] ?? "https://www.recaptcha.net/recaptcha/api/siteverify";
var url = _configuration["recaptcha:verify-url"] ?? "https://www.recaptcha.net/recaptcha/api/siteverify";
var request = new HttpRequestMessage();
request.RequestUri = new Uri(url);
request.Method = HttpMethod.Post;
request.Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Post,
Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded")
};
var httpClient = ClientFactory.CreateClient();
var httpClient = _clientFactory.CreateClient();
using var httpClientResponse = httpClient.Send(request);
using var stream = httpClientResponse.Content.ReadAsStream();
using var reader = new StreamReader(stream);
@ -338,17 +298,17 @@ public class CommonMethods
}
else
{
Log.LogDebug("Recaptcha error: {0}", resp);
_log.LogDebug("Recaptcha error: {0}", resp);
}
if (resObj["error-codes"] != null && resObj["error-codes"].HasValues)
{
Log.LogDebug("Recaptcha api returns errors: {0}", resp);
_log.LogDebug("Recaptcha api returns errors: {0}", resp);
}
}
catch (Exception ex)
{
Log.LogError(ex, "ValidateRecaptcha");
_log.LogError(ex, "ValidateRecaptcha");
}
return false;
}

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Classes;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]

View File

@ -24,50 +24,25 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.ApiSystem.Classes;
[Singletone]
public class TimeZonesProvider
{
public ILogger<TimeZonesProvider> Log { get; }
private readonly ILogger<TimeZonesProvider> _log;
private CommonConstants CommonConstants { get; }
private readonly CommonConstants _commonConstants;
public TimeZonesProvider(ILogger<TimeZonesProvider> logger, CommonConstants commonConstants)
{
Log = logger;
_log = logger;
CommonConstants = commonConstants;
_commonConstants = commonConstants;
}
#region Private
private static readonly Dictionary<string, KeyValuePair<string, string>> TimeZones = new Dictionary<string, KeyValuePair<string, string>>
private static readonly Dictionary<string, KeyValuePair<string, string>> _timeZones = new Dictionary<string, KeyValuePair<string, string>>
{
{ "", new KeyValuePair<string, string>("Europe/London", "GMT Standard Time") },
{ "fr", new KeyValuePair<string, string>("Europe/Paris", "Romance Standard Time") },
@ -92,7 +67,7 @@ public class TimeZonesProvider
{ "vi", new KeyValuePair<string, string>("Asia/Shanghai", "China Standard Time") }
};
private static readonly Dictionary<string, CultureInfo> CultureUiMap = new Dictionary<string, CultureInfo>
private static readonly Dictionary<string, CultureInfo> _cultureUiMap = new Dictionary<string, CultureInfo>
{
{ "", CultureInfo.GetCultureInfo("en-US") },
{ "fr", CultureInfo.GetCultureInfo("fr-FR") },
@ -124,7 +99,7 @@ public class TimeZonesProvider
public TimeZoneInfo GetCurrentTimeZoneInfo(string languageKey)
{
var time = TimeZones.ContainsKey(languageKey) ? TimeZones[languageKey] : TimeZones[""];
var time = _timeZones.ContainsKey(languageKey) ? _timeZones[languageKey] : _timeZones[""];
try
{
try
@ -138,7 +113,7 @@ public class TimeZonesProvider
}
catch (Exception e)
{
Log.LogError(e, "GetCurrentTimeZoneInfo");
_log.LogError(e, "GetCurrentTimeZoneInfo");
return TimeZoneInfo.Utc;
}
@ -148,12 +123,12 @@ public class TimeZonesProvider
{
if (string.IsNullOrEmpty(languageKey))
{
return CommonConstants.DefaultCulture;
return _commonConstants.DefaultCulture;
}
var culture = CultureUiMap.ContainsKey(languageKey) ? CultureUiMap[languageKey] : null;
var culture = _cultureUiMap.ContainsKey(languageKey) ? _cultureUiMap[languageKey] : null;
return culture ?? CommonConstants.DefaultCulture;
return culture ?? _commonConstants.DefaultCulture;
}
#endregion

View File

@ -24,23 +24,18 @@
// 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.Core.Tenants;
namespace ASC.ApiSystem;
[Serializable]
[DataContract]
public class TenantControlPanelSettings : ISettings<TenantControlPanelSettings>
public static class ConfigurationManagerExtension
{
[DataMember(Name = "LimitedAccess")]
public bool LimitedAccess { get; set; }
[JsonIgnore]
public Guid ID => new Guid("{880585C4-52CD-4AE2-8DA4-3B8E2772753B}");
public TenantControlPanelSettings GetDefault()
public static ConfigurationManager AddApiSystemConfiguration(this ConfigurationManager config, IHostEnvironment env)
{
return new TenantControlPanelSettings
{
LimitedAccess = false
};
config
.AddJsonFile($"apisystem.json")
.AddJsonFile($"apisystem.{env.EnvironmentName}.json", true)
.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
return config;
}
}

View File

@ -24,31 +24,6 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.ApiSystem.Controllers;
[Scope]
@ -56,13 +31,13 @@ namespace ASC.ApiSystem.Controllers;
[Route("[controller]")]
public class CalDavController : ControllerBase
{
private CommonMethods CommonMethods { get; }
private EmailValidationKeyProvider EmailValidationKeyProvider { get; }
private CoreSettings CoreSettings { get; }
private CommonConstants CommonConstants { get; }
public InstanceCrypto InstanceCrypto { get; }
private ILogger<CalDavController> Log { get; }
private IHttpClientFactory ClientFactory { get; }
private readonly CommonMethods _commonMethods;
private readonly EmailValidationKeyProvider _emailValidationKeyProvider;
private readonly CoreSettings _coreSettings;
private readonly CommonConstants _commonConstants;
private readonly InstanceCrypto _instanceCrypto;
private readonly ILogger<CalDavController> _log;
private readonly IHttpClientFactory _clientFactory;
public CalDavController(
CommonMethods commonMethods,
@ -70,14 +45,16 @@ public class CalDavController : ControllerBase
CoreSettings coreSettings,
CommonConstants commonConstants,
InstanceCrypto instanceCrypto,
ILogger<CalDavController> logger)
ILogger<CalDavController> logger,
IHttpClientFactory httpClientFactory)
{
CommonMethods = commonMethods;
EmailValidationKeyProvider = emailValidationKeyProvider;
CoreSettings = coreSettings;
CommonConstants = commonConstants;
InstanceCrypto = instanceCrypto;
Log = logger;
_commonMethods = commonMethods;
_emailValidationKeyProvider = emailValidationKeyProvider;
_coreSettings = coreSettings;
_commonConstants = commonConstants;
_instanceCrypto = instanceCrypto;
_log = logger;
_clientFactory = httpClientFactory;
}
#region For TEST api
@ -105,13 +82,13 @@ public class CalDavController : ControllerBase
try
{
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.Id, change + ConfirmType.Auth);
var validationKey = _emailValidationKeyProvider.GetEmailKey(tenant.Id, change + ConfirmType.Auth);
SendToApi(Request.Scheme, tenant, "calendar/change_to_storage", new Dictionary<string, string> { { "change", change }, { "key", validationKey } });
}
catch (Exception ex)
{
Log.LogError(ex, "Error change_to_storage");
_log.LogError(ex, "Error change_to_storage");
return StatusCode(StatusCodes.Status500InternalServerError, new
{
@ -124,7 +101,7 @@ public class CalDavController : ControllerBase
}
[HttpGet("caldav_delete_event")]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult CaldavDeleteEvent(string eventInfo)
{
if (!GetTenant(eventInfo, out var tenant, out var error))
@ -134,13 +111,13 @@ public class CalDavController : ControllerBase
try
{
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.Id, eventInfo + ConfirmType.Auth);
var validationKey = _emailValidationKeyProvider.GetEmailKey(tenant.Id, eventInfo + ConfirmType.Auth);
SendToApi(Request.Scheme, tenant, "calendar/caldav_delete_event", new Dictionary<string, string> { { "eventInfo", eventInfo }, { "key", validationKey } });
}
catch (Exception ex)
{
Log.LogError(ex, "Error caldav_delete_event");
_log.LogError(ex, "Error caldav_delete_event");
return StatusCode(StatusCodes.Status500InternalServerError, new
{
@ -153,12 +130,12 @@ public class CalDavController : ControllerBase
}
[HttpPost("is_caldav_authenticated")]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult IsCaldavAuthenticated(UserPassword userPassword)
{
if (userPassword == null || string.IsNullOrEmpty(userPassword.User) || string.IsNullOrEmpty(userPassword.Password))
{
Log.LogError("CalDav authenticated data is null");
_log.LogError("CalDav authenticated data is null");
return BadRequest(new
{
@ -175,9 +152,9 @@ public class CalDavController : ControllerBase
try
{
Log.LogInformation(string.Format("Caldav auth user: {0}, tenant: {1}", email, tenant.Id));
_log.LogInformation(string.Format("Caldav auth user: {0}, tenant: {1}", email, tenant.Id));
if (InstanceCrypto.Encrypt(email) == userPassword.Password)
if (_instanceCrypto.Encrypt(email) == userPassword.Password)
{
return Ok(new
{
@ -185,7 +162,7 @@ public class CalDavController : ControllerBase
});
}
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.Id, email + userPassword.Password + ConfirmType.Auth);
var validationKey = _emailValidationKeyProvider.GetEmailKey(tenant.Id, email + userPassword.Password + ConfirmType.Auth);
var authData = $"userName={HttpUtility.UrlEncode(email)}&password={HttpUtility.UrlEncode(userPassword.Password)}&key={HttpUtility.UrlEncode(validationKey)}";
@ -198,7 +175,7 @@ public class CalDavController : ControllerBase
}
catch (Exception ex)
{
Log.LogError(ex, "Caldav authenticated");
_log.LogError(ex, "Caldav authenticated");
return StatusCode(StatusCodes.Status500InternalServerError, new
{
@ -218,7 +195,7 @@ public class CalDavController : ControllerBase
if (string.IsNullOrEmpty(calendarParam))
{
Log.LogError("calendarParam is empty");
_log.LogError("calendarParam is empty");
error = new
{
@ -230,7 +207,7 @@ public class CalDavController : ControllerBase
return false;
}
Log.LogInformation($"CalDav calendarParam: {calendarParam}");
_log.LogInformation($"CalDav calendarParam: {calendarParam}");
var userParam = calendarParam.Split('/')[0];
return GetUserData(userParam, out _, out tenant, out error);
@ -244,7 +221,7 @@ public class CalDavController : ControllerBase
if (string.IsNullOrEmpty(userParam))
{
Log.LogError("userParam is empty");
_log.LogError("userParam is empty");
error = new
{
@ -260,7 +237,7 @@ public class CalDavController : ControllerBase
if (userData.Length < 3)
{
Log.LogError($"Error Caldav username: {userParam}");
_log.LogError($"Error Caldav username: {userParam}");
error = new
{
@ -276,20 +253,20 @@ public class CalDavController : ControllerBase
var tenantName = userData[2];
var baseUrl = CoreSettings.BaseDomain;
var baseUrl = _coreSettings.BaseDomain;
if (!string.IsNullOrEmpty(baseUrl) && tenantName.EndsWith("." + baseUrl, StringComparison.InvariantCultureIgnoreCase))
{
tenantName = tenantName.Replace("." + baseUrl, "");
}
Log.LogInformation($"CalDav: user:{userParam} tenantName:{tenantName}");
_log.LogInformation($"CalDav: user:{userParam} tenantName:{tenantName}");
var tenantModel = new TenantModel { PortalName = tenantName };
if (!CommonMethods.GetTenant(tenantModel, out tenant))
if (!_commonMethods.GetTenant(tenantModel, out tenant))
{
Log.LogError("Model without tenant");
_log.LogError("Model without tenant");
error = new
{
@ -303,7 +280,7 @@ public class CalDavController : ControllerBase
if (tenant == null)
{
Log.LogError("Tenant not found " + tenantName);
_log.LogError("Tenant not found " + tenantName);
error = new
{
@ -329,16 +306,18 @@ public class CalDavController : ControllerBase
? null
: string.Join("&", args.Select(arg => HttpUtility.UrlEncode(arg.Key) + "=" + HttpUtility.UrlEncode(arg.Value)).ToArray());
var url = $"{requestUriScheme}{Uri.SchemeDelimiter}{tenant.GetTenantDomain(CoreSettings)}{CommonConstants.WebApiBaseUrl}{path}{(string.IsNullOrEmpty(query) ? "" : "?" + query)}";
var url = $"{requestUriScheme}{Uri.SchemeDelimiter}{tenant.GetTenantDomain(_coreSettings)}{_commonConstants.WebApiBaseUrl}{path}{(string.IsNullOrEmpty(query) ? "" : "?" + query)}";
Log.LogInformation($"CalDav: SendToApi: {url}");
_log.LogInformation($"CalDav: SendToApi: {url}");
var request = new HttpRequestMessage();
request.RequestUri = new Uri(url);
request.Method = new HttpMethod(httpMethod);
var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = new HttpMethod(httpMethod)
};
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
var httpClient = ClientFactory.CreateClient();
var httpClient = _clientFactory.CreateClient();
if (data != null)
{

View File

@ -24,23 +24,6 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace ASC.ApiSystem.Controllers;
[Scope]
@ -48,30 +31,30 @@ namespace ASC.ApiSystem.Controllers;
[Route("[controller]")]
public class PeopleController : ControllerBase
{
private ILogger<PeopleController> Log { get; }
private HostedSolution HostedSolution { get; }
private UserFormatter UserFormatter { get; }
private ICache Cache { get; }
private CoreSettings CoreSettings { get; }
private CommonLinkUtility CommonLinkUtility { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
private readonly ILogger<PeopleController> _log;
private readonly HostedSolution _hostedSolution;
private readonly UserFormatter _userFormatter;
private readonly ICache _cache;
private readonly CoreSettings _coreSettings;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly IHttpContextAccessor _httpContextAccessor;
public PeopleController(
ILogger<PeopleController> option,
IOptionsSnapshot<HostedSolution> hostedSolutionOptions,
HostedSolution hostedSolution,
UserFormatter userFormatter,
ICache cache,
CoreSettings coreSettings,
CommonLinkUtility commonLinkUtility,
IHttpContextAccessor httpContextAccessor)
{
Log = option;
HostedSolution = hostedSolutionOptions.Value;
UserFormatter = userFormatter;
Cache = cache;
CoreSettings = coreSettings;
CommonLinkUtility = commonLinkUtility;
HttpContextAccessor = httpContextAccessor;
_log = option;
_hostedSolution = hostedSolution;
_userFormatter = userFormatter;
_cache = cache;
_coreSettings = coreSettings;
_commonLinkUtility = commonLinkUtility;
_httpContextAccessor = httpContextAccessor;
}
#region For TEST api
@ -91,23 +74,23 @@ public class PeopleController : ControllerBase
[HttpPost("find")]
[AllowCrossSiteJson]
public IActionResult Find(IEnumerable<Guid> userIds)
public IActionResult Find(FindPeopleModel model)
{
var sw = Stopwatch.StartNew();
userIds = userIds ?? new List<Guid>();
var userIds = model.UserIds ?? new List<Guid>();
var users = HostedSolution.FindUsers(userIds);
var users = _hostedSolution.FindUsers(userIds);
var result = users.Select(user => new
{
id = user.Id,
name = UserFormatter.GetUserName(user),
name = _userFormatter.GetUserName(user),
email = user.Email,
link = GetUserProfileLink(user)
});
Log.LogDebug("People find {0} / {1}; Elapsed {2} ms", result.Count(), userIds.Count(), sw.ElapsedMilliseconds);
_log.LogDebug("People find {0} / {1}; Elapsed {2} ms", result.Count(), userIds.Count(), sw.ElapsedMilliseconds);
sw.Stop();
return Ok(new
@ -122,12 +105,12 @@ public class PeopleController : ControllerBase
private string GetTenantDomain(int tenantId)
{
var domain = Cache.Get<string>(tenantId.ToString());
var domain = _cache.Get<string>(tenantId.ToString());
if (string.IsNullOrEmpty(domain))
{
var tenant = HostedSolution.GetTenant(tenantId);
domain = tenant.GetTenantDomain(CoreSettings);
Cache.Insert(tenantId.ToString(), domain, TimeSpan.FromMinutes(10));
var tenant = _hostedSolution.GetTenant(tenantId);
domain = tenant.GetTenantDomain(_coreSettings);
_cache.Insert(tenantId.ToString(), domain, TimeSpan.FromMinutes(10));
}
return domain;
}
@ -136,10 +119,10 @@ public class PeopleController : ControllerBase
{
var tenantDomain = GetTenantDomain(user.Tenant);
return string.Format("{0}{1}{2}/{3}",
HttpContextAccessor.HttpContext.Request.Scheme,
_httpContextAccessor.HttpContext.Request.Scheme,
Uri.SchemeDelimiter,
tenantDomain,
"Products/People/Profile.aspx?" + CommonLinkUtility.GetUserParamsPair(user));
"Products/People/Profile.aspx?" + _commonLinkUtility.GetUserParamsPair(user));
}
#endregion

View File

@ -31,22 +31,22 @@ namespace ASC.ApiSystem.Controllers;
[Route("[controller]")]
public class PortalController : ControllerBase
{
private IConfiguration Configuration { get; }
private Core.SecurityContext SecurityContext { get; }
private TenantManager TenantManager { get; }
private SettingsManager SettingsManager { get; }
private ApiSystemHelper ApiSystemHelper { get; }
private CommonMethods CommonMethods { get; }
private HostedSolution HostedSolution { get; }
private CoreSettings CoreSettings { get; }
private TenantDomainValidator TenantDomainValidator { get; }
private UserFormatter UserFormatter { get; }
private UserManagerWrapper UserManagerWrapper { get; }
private CommonConstants CommonConstants { get; }
private TimeZonesProvider TimeZonesProvider { get; }
private TimeZoneConverter TimeZoneConverter { get; }
public PasswordHasher PasswordHasher { get; }
private ILogger<PortalController> Log { get; }
private readonly IConfiguration _configuration;
private readonly Core.SecurityContext _securityContext;
private readonly TenantManager _tenantManager;
private readonly SettingsManager _settingsManager;
private readonly ApiSystemHelper _apiSystemHelper;
private readonly CommonMethods _commonMethods;
private readonly HostedSolution _hostedSolution;
private readonly CoreSettings _coreSettings;
private readonly TenantDomainValidator _tenantDomainValidator;
private readonly UserFormatter _userFormatter;
private readonly UserManagerWrapper _userManagerWrapper;
private readonly CommonConstants _commonConstants;
private readonly TimeZonesProvider _timeZonesProvider;
private readonly TimeZoneConverter _timeZoneConverter;
private readonly PasswordHasher _passwordHasher;
private readonly ILogger<PortalController> _log;
public PortalController(
IConfiguration configuration,
@ -55,7 +55,7 @@ public class PortalController : ControllerBase
SettingsManager settingsManager,
ApiSystemHelper apiSystemHelper,
CommonMethods commonMethods,
IOptionsSnapshot<HostedSolution> hostedSolutionOptions,
HostedSolution hostedSolution,
CoreSettings coreSettings,
TenantDomainValidator tenantDomainValidator,
UserFormatter userFormatter,
@ -66,22 +66,22 @@ public class PortalController : ControllerBase
TimeZoneConverter timeZoneConverter,
PasswordHasher passwordHasher)
{
Configuration = configuration;
SecurityContext = securityContext;
TenantManager = tenantManager;
SettingsManager = settingsManager;
ApiSystemHelper = apiSystemHelper;
CommonMethods = commonMethods;
HostedSolution = hostedSolutionOptions.Value;
CoreSettings = coreSettings;
TenantDomainValidator = tenantDomainValidator;
UserFormatter = userFormatter;
UserManagerWrapper = userManagerWrapper;
CommonConstants = commonConstants;
TimeZonesProvider = timeZonesProvider;
TimeZoneConverter = timeZoneConverter;
PasswordHasher = passwordHasher;
Log = option;
_configuration = configuration;
_securityContext = securityContext;
_tenantManager = tenantManager;
_settingsManager = settingsManager;
_apiSystemHelper = apiSystemHelper;
_commonMethods = commonMethods;
_hostedSolution = hostedSolution;
_coreSettings = coreSettings;
_tenantDomainValidator = tenantDomainValidator;
_userFormatter = userFormatter;
_userManagerWrapper = userManagerWrapper;
_commonConstants = commonConstants;
_timeZonesProvider = timeZonesProvider;
_timeZoneConverter = timeZoneConverter;
_passwordHasher = passwordHasher;
_log = option;
}
#region For TEST api
@ -101,7 +101,7 @@ public class PortalController : ControllerBase
[HttpPost("register")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip.registerportal")]
[Authorize(AuthenticationSchemes = "auth:allowskip:registerportal")]
public Task<IActionResult> RegisterAsync(TenantModel model)
{
if (model == null)
@ -141,7 +141,7 @@ public class PortalController : ControllerBase
if (!string.IsNullOrEmpty(model.Password))
{
model.PasswordHash = PasswordHasher.GetClientPassword(model.Password);
model.PasswordHash = _passwordHasher.GetClientPassword(model.Password);
}
}
@ -170,11 +170,11 @@ public class PortalController : ControllerBase
return BadRequest(error);
}
Log.LogDebug("PortalName = {0}; Elapsed ms. CheckExistingNamePortal: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. CheckExistingNamePortal: {1}", model.PortalName, sw.ElapsedMilliseconds);
var clientIP = CommonMethods.GetClientIp();
var clientIP = _commonMethods.GetClientIp();
if (CommonMethods.CheckMuchRegistration(model, clientIP, sw))
if (_commonMethods.CheckMuchRegistration(model, clientIP, sw))
{
return BadRequest(new
{
@ -190,24 +190,24 @@ public class PortalController : ControllerBase
var language = model.Language ?? string.Empty;
var tz = TimeZonesProvider.GetCurrentTimeZoneInfo(language);
var tz = _timeZonesProvider.GetCurrentTimeZoneInfo(language);
Log.LogDebug("PortalName = {0}; Elapsed ms. TimeZonesProvider.GetCurrentTimeZoneInfo: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. TimeZonesProvider.GetCurrentTimeZoneInfo: {1}", model.PortalName, sw.ElapsedMilliseconds);
if (!string.IsNullOrEmpty(model.TimeZoneName))
{
tz = TimeZoneConverter.GetTimeZone(model.TimeZoneName.Trim(), false) ?? tz;
tz = _timeZoneConverter.GetTimeZone(model.TimeZoneName.Trim(), false) ?? tz;
Log.LogDebug("PortalName = {0}; Elapsed ms. TimeZonesProvider.OlsonTimeZoneToTimeZoneInfo: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. TimeZonesProvider.OlsonTimeZoneToTimeZoneInfo: {1}", model.PortalName, sw.ElapsedMilliseconds);
}
var lang = TimeZonesProvider.GetCurrentCulture(language);
var lang = _timeZonesProvider.GetCurrentCulture(language);
Log.LogDebug("PortalName = {0}; model.Language = {1}, resultLang.DisplayName = {2}", model.PortalName, language, lang.DisplayName);
_log.LogDebug("PortalName = {0}; model.Language = {1}, resultLang.DisplayName = {2}", model.PortalName, language, lang.DisplayName);
var info = new TenantRegistrationInfo
{
Name = Configuration["web:portal-name"] ?? "Cloud Office Applications",
Name = _configuration["web:portal-name"] ?? "",
Address = model.PortalName,
Culture = lang,
FirstName = model.FirstName,
@ -218,19 +218,9 @@ public class PortalController : ControllerBase
MobilePhone = string.IsNullOrEmpty(model.Phone) ? null : model.Phone.Trim(),
Industry = (TenantIndustry)model.Industry,
Spam = model.Spam,
Calls = model.Calls,
LimitedControlPanel = model.LimitedControlPanel
Calls = model.Calls,
};
if (!string.IsNullOrEmpty(model.PartnerId))
{
if (Guid.TryParse(model.PartnerId, out _))
{
// valid guid
info.PartnerId = model.PartnerId;
}
}
if (!string.IsNullOrEmpty(model.AffiliateId))
{
info.AffiliateId = model.AffiliateId;
@ -246,24 +236,24 @@ public class PortalController : ControllerBase
try
{
/****REGISTRATION!!!*****/
if (!string.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiCacheUrl))
{
await ApiSystemHelper.AddTenantToCacheAsync(info.Address, SecurityContext.CurrentAccount.ID);
await _apiSystemHelper.AddTenantToCacheAsync(info.Address, _securityContext.CurrentAccount.ID);
Log.LogDebug("PortalName = {0}; Elapsed ms. CacheController.AddTenantToCache: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. CacheController.AddTenantToCache: {1}", model.PortalName, sw.ElapsedMilliseconds);
}
HostedSolution.RegisterTenant(info, out t);
_hostedSolution.RegisterTenant(info, out t);
/*********/
Log.LogDebug("PortalName = {0}; Elapsed ms. HostedSolution.RegisterTenant: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. HostedSolution.RegisterTenant: {1}", model.PortalName, sw.ElapsedMilliseconds);
}
catch (Exception e)
{
sw.Stop();
Log.LogError(e, "");
_log.LogError(e, "");
return StatusCode(StatusCodes.Status500InternalServerError, new
{
@ -273,75 +263,74 @@ public class PortalController : ControllerBase
});
}
var trialQuota = Configuration["trial-quota"];
var trialQuota = _configuration["quota:id"];
if (!string.IsNullOrEmpty(trialQuota))
{
if (int.TryParse(trialQuota, out var trialQuotaId))
{
var dueDate = DateTime.MaxValue;
if (int.TryParse(Configuration["trial-due"], out var dueTrial))
if (int.TryParse(_configuration["quota:due"], out var dueTrial))
{
dueDate = DateTime.UtcNow.AddDays(dueTrial);
}
var tariff = new Tariff
{
QuotaId = trialQuotaId,
Quotas = new List<Quota> { new Quota(trialQuotaId, 1) },
DueDate = dueDate
};
HostedSolution.SetTariff(t.Id, tariff);
_hostedSolution.SetTariff(t.Id, tariff);
}
}
var isFirst = true;
string sendCongratulationsAddress = null;
if (!string.IsNullOrEmpty(model.PasswordHash))
{
isFirst = !CommonMethods.SendCongratulations(Request.Scheme, t, model.SkipWelcome, out sendCongratulationsAddress);
isFirst = !_commonMethods.SendCongratulations(Request.Scheme, t, model.SkipWelcome, out sendCongratulationsAddress);
}
else if (Configuration["core:base-domain"] == "localhost")
else if (_configuration["core:base-domain"] == "localhost")
{
try
{
/* set wizard not completed*/
TenantManager.SetCurrentTenant(t);
_tenantManager.SetCurrentTenant(t);
var settings = SettingsManager.Load<WizardSettings>();
var settings = _settingsManager.Load<WizardSettings>();
settings.Completed = false;
SettingsManager.Save(settings);
_settingsManager.Save(settings);
}
catch (Exception e)
{
Log.LogError(e, "RegisterAsync");
_log.LogError(e, "RegisterAsync");
}
}
var reference = CommonMethods.CreateReference(Request.Scheme, t.GetTenantDomain(CoreSettings), info.Email, isFirst);
var reference = _commonMethods.CreateReference(Request.Scheme, t.GetTenantDomain(_coreSettings), info.Email, isFirst);
Log.LogDebug("PortalName = {0}; Elapsed ms. CreateReferenceByCookie...: {1}", model.PortalName, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. CreateReferenceByCookie...: {1}", model.PortalName, sw.ElapsedMilliseconds);
sw.Stop();
return Ok(new
{
reference,
tenant = CommonMethods.ToTenantWrapper(t),
tenant = _commonMethods.ToTenantWrapper(t),
referenceWelcome = sendCongratulationsAddress
});
}
[HttpDelete("remove")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult Remove([FromQuery] TenantModel model)
{
if (!CommonMethods.GetTenant(model, out var tenant))
if (!_commonMethods.GetTenant(model, out var tenant))
{
Log.LogError("Model without tenant");
_log.LogError("Model without tenant");
return BadRequest(new
{
@ -352,7 +341,7 @@ public class PortalController : ControllerBase
if (tenant == null)
{
Log.LogError("Tenant not found");
_log.LogError("Tenant not found");
return BadRequest(new
{
@ -361,22 +350,22 @@ public class PortalController : ControllerBase
});
}
HostedSolution.RemoveTenant(tenant);
_hostedSolution.RemoveTenant(tenant);
return Ok(new
{
tenant = CommonMethods.ToTenantWrapper(tenant)
tenant = _commonMethods.ToTenantWrapper(tenant)
});
}
[HttpPut("status")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult ChangeStatus(TenantModel model)
{
if (!CommonMethods.GetTenant(model, out var tenant))
if (!_commonMethods.GetTenant(model, out var tenant))
{
Log.LogError("Model without tenant");
_log.LogError("Model without tenant");
return BadRequest(new
{
@ -387,7 +376,7 @@ public class PortalController : ControllerBase
if (tenant == null)
{
Log.LogError("Tenant not found");
_log.LogError("Tenant not found");
return BadRequest(new
{
@ -405,11 +394,11 @@ public class PortalController : ControllerBase
tenant.SetStatus(active);
HostedSolution.SaveTenant(tenant);
_hostedSolution.SaveTenant(tenant);
return Ok(new
{
tenant = CommonMethods.ToTenantWrapper(tenant)
tenant = _commonMethods.ToTenantWrapper(tenant)
});
}
@ -446,7 +435,7 @@ public class PortalController : ControllerBase
[HttpGet("get")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult GetPortals([FromQuery] TenantModel model)
{
try
@ -457,13 +446,13 @@ public class PortalController : ControllerBase
if (!string.IsNullOrWhiteSpace((model.Email ?? "")))
{
empty = false;
tenants.AddRange(HostedSolution.FindTenants((model.Email ?? "").Trim()));
tenants.AddRange(_hostedSolution.FindTenants((model.Email ?? "").Trim()));
}
if (!string.IsNullOrWhiteSpace((model.PortalName ?? "")))
{
empty = false;
var tenant = HostedSolution.GetTenant((model.PortalName ?? "").Trim());
var tenant = _hostedSolution.GetTenant((model.PortalName ?? "").Trim());
if (tenant != null)
{
@ -474,7 +463,7 @@ public class PortalController : ControllerBase
if (model.TenantId.HasValue)
{
empty = false;
var tenant = HostedSolution.GetTenant(model.TenantId.Value);
var tenant = _hostedSolution.GetTenant(model.TenantId.Value);
if (tenant != null)
{
@ -484,14 +473,14 @@ public class PortalController : ControllerBase
if (empty)
{
tenants.AddRange(HostedSolution.GetTenants(DateTime.MinValue).OrderBy(t => t.Id).ToList());
tenants.AddRange(_hostedSolution.GetTenants(DateTime.MinValue).OrderBy(t => t.Id).ToList());
}
var tenantsWrapper = tenants
.Distinct()
.Where(t => t.Status == TenantStatus.Active)
.OrderBy(t => t.Id)
.Select(CommonMethods.ToTenantWrapper);
.Select(_commonMethods.ToTenantWrapper);
return Ok(new
{
@ -500,7 +489,7 @@ public class PortalController : ControllerBase
}
catch (Exception ex)
{
Log.LogError(ex, "");
_log.LogError(ex, "");
return StatusCode(StatusCodes.Status500InternalServerError, new
{
@ -518,11 +507,11 @@ public class PortalController : ControllerBase
private async Task ValidateDomainAsync(string domain)
{
// size
TenantDomainValidator.ValidateDomainLength(domain);
_tenantDomainValidator.ValidateDomainLength(domain);
// characters
TenantDomainValidator.ValidateDomainCharacters(domain);
var sameAliasTenants = await ApiSystemHelper.FindTenantsInCacheAsync(domain, SecurityContext.CurrentAccount.ID);
var sameAliasTenants = await _apiSystemHelper.FindTenantsInCacheAsync(domain, _securityContext.CurrentAccount.ID);
if (sameAliasTenants != null)
{
@ -546,13 +535,13 @@ public class PortalController : ControllerBase
object error = null;
try
{
if (!string.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiCacheUrl))
{
await ValidateDomainAsync(portalName.Trim());
}
else
{
HostedSolution.CheckTenantAddress(portalName.Trim());
_hostedSolution.CheckTenantAddress(portalName.Trim());
}
}
catch (TenantAlreadyExistsException ex)
@ -573,7 +562,7 @@ public class PortalController : ControllerBase
}
catch (Exception ex)
{
Log.LogError(ex, "CheckExistingNamePortal");
_log.LogError(ex, "CheckExistingNamePortal");
error = new { error = "error", message = ex.Message, stacktrace = ex.StackTrace };
return (false, error);
}
@ -590,7 +579,7 @@ public class PortalController : ControllerBase
return false;
}
if (!UserFormatter.IsValidUserName(name, string.Empty))
if (!_userFormatter.IsValidUserName(name, string.Empty))
{
error = new { error = "error", message = "name is incorrect" };
return false;
@ -608,9 +597,9 @@ public class PortalController : ControllerBase
return true;
}
var passwordSettings = SettingsManager.GetDefault<PasswordSettings>();
var passwordSettings = _settingsManager.GetDefault<PasswordSettings>();
if (!UserManagerWrapper.CheckPasswordRegex(passwordSettings, pwd))
if (!_userManagerWrapper.CheckPasswordRegex(passwordSettings, pwd))
{
error = new { error = "passPolicyError", message = "Password is incorrect" };
return false;
@ -625,21 +614,21 @@ public class PortalController : ControllerBase
private bool CheckRecaptcha(TenantModel model, string clientIP, Stopwatch sw, out object error)
{
error = null;
if (CommonConstants.RecaptchaRequired
&& !CommonMethods.IsTestEmail(model.Email))
if (_commonConstants.RecaptchaRequired
&& !_commonMethods.IsTestEmail(model.Email))
{
if (!string.IsNullOrEmpty(model.AppKey) && CommonConstants.AppSecretKeys.Contains(model.AppKey))
if (!string.IsNullOrEmpty(model.AppKey) && _commonConstants.AppSecretKeys.Contains(model.AppKey))
{
Log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha via app key: {1}. {2}", model.PortalName, model.AppKey, sw.ElapsedMilliseconds);
_log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha via app key: {1}. {2}", model.PortalName, model.AppKey, sw.ElapsedMilliseconds);
return true;
}
var data = $"{model.PortalName} {model.FirstName} {model.LastName} {model.Email} {model.Phone} {model.RecaptchaType}";
/*** validate recaptcha ***/
if (!CommonMethods.ValidateRecaptcha(model.RecaptchaResponse, model.RecaptchaType, clientIP))
if (!_commonMethods.ValidateRecaptcha(model.RecaptchaResponse, model.RecaptchaType, clientIP))
{
Log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha error: {1} {2}", model.PortalName, sw.ElapsedMilliseconds, data);
_log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha error: {1} {2}", model.PortalName, sw.ElapsedMilliseconds, data);
sw.Stop();
error = new { error = "recaptchaInvalid", message = "Recaptcha is invalid" };
@ -647,7 +636,7 @@ public class PortalController : ControllerBase
}
Log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha: {1} {2}", model.PortalName, sw.ElapsedMilliseconds, data);
_log.LogDebug("PortalName = {0}; Elapsed ms. ValidateRecaptcha: {1} {2}", model.PortalName, sw.ElapsedMilliseconds, data);
}
return true;

View File

@ -24,31 +24,6 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.ApiSystem.Controllers;
[Scope]
@ -86,7 +61,7 @@ public class SettingsController : ControllerBase
#region API methods
[HttpGet("get")]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult GetSettings([FromQuery] SettingsModel model)
{
if (!GetTenant(model, out var tenantId, out var error))
@ -112,7 +87,7 @@ public class SettingsController : ControllerBase
}
[HttpPost("save")]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult SaveSettings([FromBody] SettingsModel model)
{
if (!GetTenant(model, out var tenantId, out var error))

View File

@ -24,31 +24,6 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.ApiSystem.Controllers;
[Scope]
@ -61,12 +36,12 @@ public class TariffController : ControllerBase
private ILogger<TariffController> Log { get; }
public TariffController(
CommonMethods commonMethods,
IOptionsSnapshot<HostedSolution> hostedSolutionOptions,
HostedSolution hostedSolution,
ILogger<TariffController> option
)
{
CommonMethods = commonMethods;
HostedSolution = hostedSolutionOptions.Value;
HostedSolution = hostedSolution;
Log = option;
}
@ -87,7 +62,7 @@ public class TariffController : ControllerBase
[HttpPut("set")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult SetTariff(TariffModel model)
{
if (!CommonMethods.GetTenant(model, out var tenant))
@ -114,7 +89,7 @@ public class TariffController : ControllerBase
var quota = new TenantQuota(tenant.Id)
{
ActiveUsers = 10000,
CountManager = 10000,
Features = model.Features ?? "",
MaxFileSize = 1024 * 1024 * 1024,
MaxTotalSize = 1024L * 1024 * 1024 * 1024 - 1,
@ -123,7 +98,7 @@ public class TariffController : ControllerBase
if (model.ActiveUsers != default)
{
quota.ActiveUsers = model.ActiveUsers;
quota.CountManager = model.ActiveUsers;
}
if (model.MaxTotalSize != default)
@ -136,12 +111,12 @@ public class TariffController : ControllerBase
quota.MaxFileSize = model.MaxFileSize;
}
HostedSolution.SaveTenantQuota(quota);
HostedSolution.SaveTenantQuota(quota);
var tariff = new Tariff
{
QuotaId = quota.Tenant,
DueDate = model.DueDate != default ? model.DueDate : DateTime.MaxValue,
{
Quotas = new List<Quota> { new Quota(quota.Tenant, 1) },
DueDate = model.DueDate != default ? model.DueDate : DateTime.MaxValue.AddSeconds(-1),
};
HostedSolution.SetTariff(tenant.Id, tariff);
@ -151,7 +126,7 @@ public class TariffController : ControllerBase
[HttpGet("get")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth.allowskip")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public IActionResult GetTariff([FromQuery] TariffModel model)
{
if (!CommonMethods.GetTenant(model, out var tenant))
@ -184,8 +159,8 @@ public class TariffController : ControllerBase
public IActionResult GetTariffs()
{
var tariffs = HostedSolution.GetTenantQuotas()
.Where(q => !q.Trial && !q.Free && !q.Open)
.OrderBy(q => q.ActiveUsers)
.Where(q => !q.Trial && !q.Free)
.OrderBy(q => q.CountManager)
.ThenByDescending(q => q.Tenant)
.Select(q => ToTariffWrapper(null, q));
@ -216,7 +191,7 @@ public class TariffController : ControllerBase
{
return new
{
activeUsers = q.ActiveUsers,
countManager = q.CountManager,
dueDate = t == null ? DateTime.MaxValue : t.DueDate,
features = q.Features,
maxFileSize = q.MaxFileSize,

View File

@ -34,48 +34,59 @@ global using System.Linq;
global using System.Net;
global using System.Net.Http;
global using System.Net.Http.Headers;
global using System.Reflection;
global using System.Security;
global using System.Security.Authentication;
global using System.Security.Claims;
global using System.Security.Cryptography;
global using System.Text;
global using System.Text.Encodings.Web;
global using System.Text.Json.Serialization;
global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using System.Threading.Tasks;
global using System.Web;
global using System.Web.Http.Filters;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Core;
global using ASC.Api.Core.Extensions;
global using ASC.Api.Core.Middleware;
global using ASC.ApiSystem;
global using ASC.ApiSystem.Classes;
global using ASC.ApiSystem.Interfaces;
global using ASC.ApiSystem.Models;
global using ASC.Common;
global using ASC.Common.Caching;
global using ASC.Common.DependencyInjection;
global using ASC.Common.Logging;
global using ASC.Common.Mapping;
global using ASC.Common.Security.Authorizing;
global using ASC.Common.Utils;
global using ASC.Core;
global using ASC.Core.Billing;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Context;
global using ASC.Core.Common.Hosting;
global using ASC.Core.Common.Security;
global using ASC.Core.Common.Settings;
global using ASC.Core.Tenants;
global using ASC.Core.Users;
global using ASC.EventBus.Extensions.Logger;
global using ASC.Feed.Context;
global using ASC.MessagingSystem.EF.Context;
global using ASC.Security.Cryptography;
global using ASC.Web.Core.Helpers;
global using ASC.Web.Core.PublicResources;
global using ASC.Web.Core.Users;
global using ASC.Web.Core.Utility;
global using ASC.Web.Core.Utility.Settings;
global using ASC.Web.Studio.Utility;
global using ASC.Webhooks.Core;
global using ASC.Webhooks.Core.EF.Context;
global using Autofac;
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.Routing;
@ -83,8 +94,12 @@ global using Microsoft.AspNetCore.WebUtilities;
global using Microsoft.Extensions.Caching.Memory;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using Newtonsoft.Json.Linq;
global using Newtonsoft.Json.Linq;
global using NLog;

View File

@ -1,29 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Interfaces;
public interface IModel

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Models;
public class CoreSettingsModel

View File

@ -0,0 +1,32 @@
// (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.ApiSystem.Models;
public class FindPeopleModel
{
public IEnumerable<Guid> UserIds { get; set; }
}

View File

@ -1,18 +1,28 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// (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.ApiSystem.Models;

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Models;
public class SettingsModel : IModel

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Models;
public class TariffModel : IModel

View File

@ -1,28 +1,29 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
// (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.ApiSystem.Models;
public class TenantModel : IModel
@ -55,13 +56,10 @@ public class TenantModel : IModel
public string Module { get; set; }
//todo: delete after www update
[StringLength(Web.Core.Utility.PasswordSettings.MaxLength)]
[StringLength(PasswordSettings.MaxLength)]
public string Password { get; set; }
public string PasswordHash { get; set; }
[StringLength(255)]
public string PartnerId { get; set; }
public string PasswordHash { get; set; }
[StringLength(32)]
public string Phone { get; set; }
@ -84,7 +82,5 @@ public class TenantModel : IModel
public bool Calls { get; set; }
public string AppKey { get; set; }
public bool LimitedControlPanel { get; set; }
public string AppKey { get; set; }
}

View File

@ -24,31 +24,6 @@
// 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
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
var options = new WebApplicationOptions
{
@ -56,46 +31,54 @@ var options = new WebApplicationOptions
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(options);
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault(args, (hostContext, config, env, path) =>
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddApiSystemConfiguration(builder.Environment)
.AddEnvironmentVariables()
.AddCommandLine(args);
var logger = LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
try
{
config.AddJsonFile($"appsettings.services.json", true)
.AddJsonFile("notify.json")
.AddJsonFile($"notify.{env.EnvironmentName}.json", true);
},
(hostContext, services, diHelper) =>
logger.Info("Configuring web host ({applicationContext})...", AppName);
builder.Host.ConfigureDefault();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment);
logger.Info("Starting web host ({applicationContext})...", AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
diHelper.RegisterProducts(hostContext.Configuration, hostContext.HostingEnvironment.ContentRootPath);
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", AppName);
}
diHelper.TryAdd<AuthHandler>();
diHelper.AddControllers();
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
services.AddAutoMapper(Assembly.GetAssembly(typeof(MappingProfile)));
services.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, AuthHandler>("auth.allowskip", _ => { })
.AddScheme<AuthenticationSchemeOptions, AuthHandler>("auth.allowskip.registerportal", _ => { });
});
var startup = new BaseWorkerStartup(builder.Configuration);
startup.ConfigureServices(builder.Services);
builder.Host.ConfigureContainer<ContainerBuilder>((context, builder) =>
throw;
}
finally
{
builder.Register(context.Configuration);
});
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
LogManager.Shutdown();
}
var app = builder.Build();
startup.Configure(app);
await app.RunAsync();
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -0,0 +1,132 @@
// (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.ApiSystem;
public class Startup
{
private readonly IConfiguration _configuration;
private readonly IHostEnvironment _hostEnvironment;
private readonly DIHelper _diHelper;
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
_configuration = configuration;
_hostEnvironment = hostEnvironment;
_diHelper = new DIHelper();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCustomHealthCheck(_configuration);
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddHttpClient();
services.AddScoped<EFLoggerFactory>();
services.AddBaseDbContextPool<AccountLinkContext>();
services.AddBaseDbContextPool<CoreDbContext>();
services.AddBaseDbContextPool<TenantDbContext>();
services.AddBaseDbContextPool<UserDbContext>();
services.AddBaseDbContextPool<TelegramDbContext>();
services.AddBaseDbContextPool<FirebaseDbContext>();
services.AddBaseDbContextPool<CustomDbContext>();
services.AddBaseDbContextPool<WebstudioDbContext>();
services.AddBaseDbContextPool<InstanceRegistrationContext>();
services.AddBaseDbContextPool<IntegrationEventLogContext>();
services.AddBaseDbContextPool<FeedDbContext>();
services.AddBaseDbContextPool<MessagesContext>();
services.AddBaseDbContextPool<WebhooksDbContext>();
services.AddSession();
_diHelper.Configure(services);
Action<JsonOptions> jsonOptions = options =>
{
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.Converters.Add(new ApiDateTimeConverter());
};
services.AddControllers()
.AddXmlSerializerFormatters()
.AddJsonOptions(jsonOptions);
services.AddSingleton(jsonOptions);
_diHelper.AddControllers();
_diHelper.TryAdd<CultureMiddleware>();
_diHelper.TryAdd<IpSecurityFilter>();
_diHelper.TryAdd<PaymentFilter>();
_diHelper.TryAdd<ProductSecurityFilter>();
_diHelper.TryAdd<TenantStatusFilter>();
_diHelper.TryAdd<ConfirmAuthHandler>();
_diHelper.TryAdd<BasicAuthHandler>();
_diHelper.TryAdd<CookieAuthHandler>();
_diHelper.TryAdd<WebhooksGlobalFilterAttribute>();
services.AddDistributedCache(_configuration);
services.AddEventBus(_configuration);
services.AddDistributedTaskQueue();
services.AddCacheNotify(_configuration);
services.RegisterFeature();
_diHelper.TryAdd(typeof(IWebhookPublisher), typeof(WebhookPublisher));
_diHelper.RegisterProducts(_configuration, _hostEnvironment.ContentRootPath);
services.AddAutoMapper(BaseStartup.GetAutoMapperProfileAssemblies());
if (!_hostEnvironment.IsDevelopment())
{
services.AddStartupTask<WarmupServicesStartupTask>()
.TryAddSingleton(services);
}
services.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, AuthHandler>("auth:allowskip:default", _ => { })
.AddScheme<AuthenticationSchemeOptions, AuthHandler>("auth:allowskip:registerportal", _ => { });
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCultureMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapCustom();
});
}
}

View File

@ -61,11 +61,6 @@ public class BackupController : ControllerBase
[HttpGet("getbackupschedule")]
public BackupAjaxHandler.Schedule GetBackupSchedule()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
return _backupHandler.GetSchedule();
}
@ -80,10 +75,6 @@ public class BackupController : ControllerBase
[HttpPost("createbackupschedule")]
public bool CreateBackupSchedule(BackupScheduleDto backupSchedule)
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
var storageType = backupSchedule.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backupSchedule.StorageType);
var storageParams = backupSchedule.StorageParams == null ? new Dictionary<string, string>() : backupSchedule.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString());
var backupStored = backupSchedule.BackupsStored == null ? 0 : Int32.Parse(backupSchedule.BackupsStored);
@ -104,11 +95,6 @@ public class BackupController : ControllerBase
[HttpDelete("deletebackupschedule")]
public bool DeleteBackupSchedule()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
_backupHandler.DeleteSchedule();
return true;
@ -124,11 +110,7 @@ public class BackupController : ControllerBase
[AllowNotPayment]
[HttpPost("startbackup")]
public BackupProgress StartBackup(BackupDto backup)
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
{
var storageType = backup.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backup.StorageType);
var storageParams = backup.StorageParams == null ? new Dictionary<string, string>() : backup.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString());
@ -151,11 +133,6 @@ public class BackupController : ControllerBase
[HttpGet("getbackupprogress")]
public BackupProgress GetBackupProgress()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
return _backupHandler.GetBackupProgress();
}
@ -167,11 +144,6 @@ public class BackupController : ControllerBase
[HttpGet("getbackuphistory")]
public List<BackupHistoryRecord> GetBackupHistory()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
return _backupHandler.GetBackupHistory();
}
@ -182,11 +154,6 @@ public class BackupController : ControllerBase
[HttpDelete("deletebackup/{id}")]
public bool DeleteBackup(Guid id)
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
_backupHandler.DeleteBackup(id);
return true;
}
@ -199,11 +166,6 @@ public class BackupController : ControllerBase
[HttpDelete("deletebackuphistory")]
public bool DeleteBackupHistory()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
_backupHandler.DeleteAllBackups();
return true;
}
@ -220,10 +182,6 @@ public class BackupController : ControllerBase
[HttpPost("startrestore")]
public BackupProgress StartBackupRestore(BackupRestoreDto backupRestore)
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
var storageParams = backupRestore.StorageParams == null ? new Dictionary<string, string>() : backupRestore.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString());
_eventBus.Publish(new BackupRestoreRequestIntegrationEvent(
@ -248,11 +206,6 @@ public class BackupController : ControllerBase
[AllowNotPayment]
public BackupProgress GetRestoreProgress()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
return _backupHandler.GetRestoreProgress();
}
@ -260,11 +213,6 @@ public class BackupController : ControllerBase
[HttpGet("backuptmp")]
public object GetTempPath()
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
return _backupHandler.GetTmpFolder();
}
@ -274,10 +222,6 @@ public class BackupController : ControllerBase
{
try
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
_backupHandler.DemandPermissionsRestore();
return true;
}
@ -293,10 +237,6 @@ public class BackupController : ControllerBase
{
try
{
if (_coreBaseSettings.Standalone)
{
_tenantExtra.DemandControlPanelPermission();
}
_backupHandler.DemandPermissionsAutoBackup();
return true;
}

View File

@ -1,5 +0,0 @@
{
"ActiveMQ": {
"Uri": "amqp://127.0.0.1:5672"
}
}

View File

@ -0,0 +1,5 @@
{
"ActiveMQ": {
"Uri": "amqp://127.0.0.1:5672?nms.username=guest&nms.password=password"
}
}

49
config/apisystem.json Normal file
View File

@ -0,0 +1,49 @@
{
"core": {
"base-domain":"localhost",
"machinekey": "1123askdasjklasbnd",
"notify": {
"postman": "log"
},
"payment-partners" : "",
"username" : {
"regex" : "^[\\p{L}\\p{M}' \\-]+$"
}
},
"web": {
"alias" : {
"min" : 3
},
"api-cache": "",
"autotest" : {
"secret-email" : ""
},
"app": {
"keys": ""
}
},
"recaptcha" : {
"required" : false,
"private-key" : {
"default" : "",
"android": "",
"ios": ""
}
},
"auth" : {
"allowskip" : {
"default" : false,
"registerportal": true
}
},
"ConnectionStrings": {
"default": {
"name": "default",
"connectionString": "Server=localhost;Database=onlyoffice;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
}
},
"quota": {
"id": -3
}
}

View File

@ -99,7 +99,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,audit,ldap,sso,restore,total_size:2147483648,manager:1,rooms:12,usersInRoom:3",
Features = "free,total_size:2147483648,manager:1,room:12,usersInRoom:3",
MaxFileSize = 100L,
Name = "startup",
Price = 0.00m,

View File

@ -94,7 +94,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
migrationBuilder.InsertData(
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "product_id" },
values: new object[] { -3, null, "free,audit,ldap,sso,restore,total_size:2147483648,file_size:100,manager:5,room:3", "startup", null });
values: new object[] { -3, null, "free,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", null });
migrationBuilder.InsertData(
table: "tenants_quota",

View File

@ -87,7 +87,7 @@ namespace ASC.Migrations.MySql.Migrations
new
{
Tenant = -3,
Features = "free,audit,ldap,sso,restore,total_size:2147483648,file_size:100,manager:1,rooms:12,usersInRoom:3",
Features = "free,total_size:2147483648,manager:1,room:12,usersInRoom:3",
Name = "startup",
Price = 0.00m,
Visible = false

View File

@ -92,7 +92,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,audit,ldap,sso,restore,total_size:2147483648,manager:1,rooms:12,usersInRoom:3",
Features = "free,total_size:2147483648,manager:1,room:12,usersInRoom:3",
MaxFileSize = 100L,
Name = "startup",
Price = 0.00m,

View File

@ -100,7 +100,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
schema: "onlyoffice",
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "visible" },
values: new object[] { -3, null, "free,audit,ldap,sso,restore,total_size:2147483648,file_size:100,manager:5,room:3", "startup", false });
values: new object[] { -3, null, "free,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", false });
migrationBuilder.InsertData(
schema: "onlyoffice",

View File

@ -82,7 +82,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
new
{
Tenant = -3,
Features = "free,audit,ldap,sso,restore,total_size:2147483648,file_size:100,manager:1,rooms:12,usersInRoom:3",
Features = "free,total_size:2147483648,manager:1,room:12,usersInRoom:3",
Name = "startup",
Price = 0.00m,
Visible = false

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 2.99976L10.2574 2.99976L12.2574 0.999756H3C1.89543 0.999756 1 1.89519 1 2.99976V12.9998C1 14.1043 1.89543 14.9998 3 14.9998H13C14.1046 14.9998 15 14.1043 15 12.9998V6.7424L13 8.7424V12.9998H3V2.99976ZM15.2071 3.70686L8.70711 10.2069C8.31659 10.5974 7.68342 10.5974 7.2929 10.2069L4.29289 7.20685L5.70711 5.79264L8.00001 8.08554L13.7929 2.29265L15.2071 3.70686Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 534 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.8589 10.9925C16.0587 11.2839 16.0187 11.6586 15.779 11.8667C15.4994 12.0749 15.0999 12.0333 14.9002 11.7835L13.502 9.91022L12.1438 11.7419C11.9441 12.0333 11.5446 12.0333 11.265 11.8251C10.9854 11.617 10.9454 11.2423 11.1452 10.9509L12.743 8.78629L11.1452 6.62162C10.9454 6.33022 11.0254 5.91394 11.265 5.70581C11.5446 5.49767 11.9441 5.58093 12.1438 5.83069L13.502 7.70397L14.9002 5.91394C15.0999 5.62255 15.4595 5.58093 15.779 5.78906C16.0587 5.9972 16.0587 6.41348 15.8589 6.70488L14.301 8.8279L15.8589 10.9925ZM8.58857 10.7427C7.54996 10.7427 6.71105 9.91022 6.71105 8.8279C6.71105 7.78719 7.54996 6.91298 8.58857 6.91298C9.62719 6.91298 10.4661 7.78719 10.4661 8.8279C10.4262 9.91022 9.58726 10.7427 8.58857 10.7427ZM3.07591 10.7427C2.03729 10.7427 1.19841 9.91022 1.19841 8.8279C1.19841 7.78719 2.03729 6.91298 3.07591 6.91298C4.11453 6.91298 4.95341 7.78719 4.95341 8.8279C4.95341 9.91022 4.11453 10.7427 3.07591 10.7427ZM8.58857 5.66418C7.4301 5.66418 6.39151 6.33022 5.87219 7.32928C5.35288 6.33022 4.31426 5.66418 3.11586 5.66418C2.39681 5.66418 1.75766 5.91394 1.23836 6.2886V3.62442C1.23836 3.2914 0.958726 3 0.639148 3C0.279629 3 0 3.2914 0 3.62442V8.86951C0.0399491 10.6178 1.39814 11.9916 3.07591 11.9916C4.27432 11.9916 5.31294 11.2839 5.83225 10.2848C6.35156 11.2839 7.39017 11.9916 8.54865 11.9916C10.2663 11.9916 11.6645 10.5762 11.6645 8.78629C11.7044 7.07949 10.3063 5.66418 8.58857 5.66418Z" fill="#0061D5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 1L0 3.62468L4 6.24936L0 8.87404L4 11.4987L8 8.87404L12 11.4987L16 8.87404L12 6.24936L16 3.62468L12 1L8 3.62468L4 1ZM8 3.62468L12 6.24936L8 8.87404L4 6.24936L8 3.62468Z" fill="#0061FE"/>
<path d="M8 9.75L4 12.3747L8 14.9994L12 12.3747L8 9.75Z" fill="#0061FE"/>
</svg>

After

Width:  |  Height:  |  Size: 415 B

View File

@ -0,0 +1,30 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_743_33362)">
<path d="M0 10.4629L2.54685 14.998H13.4526L15.9994 10.4629H0Z" fill="#4788F4"/>
<path d="M15.888 10.5286L13.415 14.9323H2.58546L2.58535 14.9321L2.54736 14.998H13.453L15.9999 10.4629L15.888 10.5286Z" fill="black" fill-opacity="0.1"/>
<path d="M5.15994 10.4629L5.12207 10.5286H15.8879L15.9999 10.4629H5.15994Z" fill="white" fill-opacity="0.2"/>
<path d="M5.15951 10.4629L7.77161 14.998H2.54736L5.15951 10.4629Z" fill="url(#paint0_linear_743_33362)"/>
<path d="M0 10.4645L2.54684 14.9996L10.6119 1H5.38755L0 10.4645Z" fill="#1EA362"/>
<path d="M7.9997 5.53426L2.54685 14.9996L0 10.4645L0.0751417 10.4648L2.54756 14.8673L7.96198 5.46875L7.9997 5.53426Z" fill="black" fill-opacity="0.1"/>
<path d="M0 10.4645L5.38755 1L5.4254 1.06573L0.0751417 10.4648L0 10.4645Z" fill="white" fill-opacity="0.2"/>
<path d="M7.61492 6.20364L8.00053 5.53427L5.38821 1L5.00488 1.67339L7.61492 6.20364Z" fill="url(#paint1_linear_743_33362)"/>
<path d="M5.3877 1H10.612L15.9995 10.4645H10.8401L5.3877 1Z" fill="#FFCF49"/>
<path d="M10.8401 10.4645L5.3877 1L5.50104 1.06573L10.9156 10.4645H10.8401Z" fill="black" fill-opacity="0.1"/>
<path d="M5.3877 1H10.612L15.9995 10.4645H15.9243L10.5741 1.06573H5.50104L5.3877 1Z" fill="white" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_743_33362" x1="3.86976" y1="12.6647" x2="7.78469" y2="14.9758" gradientUnits="userSpaceOnUse">
<stop stop-opacity="0.2"/>
<stop offset="0.116022" stop-opacity="0.13"/>
<stop offset="1" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_743_33362" x1="6.82489" y1="3.25111" x2="5.85871" y2="3.78805" gradientUnits="userSpaceOnUse">
<stop stop-opacity="0.1"/>
<stop offset="0.19337" stop-opacity="0.04"/>
<stop offset="0.681779" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_743_33362">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,14 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_743_33365)">
<path opacity="0.504232" fill-rule="evenodd" clip-rule="evenodd" d="M6.89884 0.0620607L8.2498 0.640118C8.45658 0.728587 8.61647 0.903445 8.68898 1.12048L9.22621 2.72751C9.31262 2.98621 9.52192 3.182 9.78141 3.24696L15.4025 4.65406C15.7532 4.74186 15.9999 5.06358 15.9999 5.43312V12.146C15.9999 12.5889 15.649 12.948 15.2163 12.948C15.1382 12.948 15.0605 12.9361 14.9859 12.9126L6.36612 10.1981C6.03735 10.0945 5.81299 9.78359 5.81299 9.43142V0.802025C5.81299 0.359076 6.16386 0 6.59661 0C6.70039 0 6.80313 0.0210928 6.89884 0.0620607Z" fill="#D0DFFF"/>
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M4.93986 1.66558L6.29088 2.24363C6.49766 2.3321 6.65754 2.50696 6.73006 2.724L7.2672 4.33102C7.35369 4.58973 7.56299 4.78552 7.82249 4.85048L13.4435 6.25762C13.7942 6.34535 14.041 6.66712 14.041 7.03662V13.7495C14.041 14.1925 13.6901 14.5516 13.2574 14.5516C13.1792 14.5516 13.1016 14.5396 13.0269 14.5161L4.40717 11.8016C4.07837 11.698 3.854 11.3871 3.854 11.035V2.40554C3.854 1.9626 4.20484 1.60352 4.63762 1.60352C4.74138 1.60352 4.84412 1.62461 4.93986 1.66558Z" fill="#B3CAFF"/>
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M12.0819 11.9974L14.0409 12.6144V7.03653C14.0409 6.66694 13.7942 6.34526 13.4434 6.25744L7.82244 4.85036C7.56294 4.7854 7.35365 4.58961 7.26715 4.3309L6.73001 2.72387C6.65749 2.50684 6.49761 2.33198 6.29083 2.24351L5.81299 2.03906V6.19939C5.82955 6.20476 5.84635 6.20958 5.86338 6.21384L11.4845 7.62097C11.8351 7.7087 12.0819 8.03047 12.0819 8.39997V11.9974Z" fill="#AAC4FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.98087 3.03081L4.33187 3.60887C4.53864 3.69734 4.6985 3.8722 4.77106 4.08923L5.3082 5.69626C5.39468 5.95496 5.60397 6.15075 5.86346 6.21571L11.4845 7.62284C11.8352 7.71066 12.0819 8.03234 12.0819 8.40184V15.1147C12.0819 15.5578 11.7311 15.9168 11.2983 15.9168C11.2203 15.9168 11.1425 15.9049 11.0678 15.8813L2.44817 13.1668C2.11938 13.0632 1.89502 12.7523 1.89502 12.4002V3.77078C1.89502 3.32783 2.24585 2.96875 2.67863 2.96875C2.78239 2.96875 2.88513 2.98984 2.98087 3.03081Z" fill="#1A47FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.993555 6.58589L9.69995 9.06121C9.96274 9.13587 10.1687 9.34511 10.2437 9.61364L11.8836 15.4883C11.9431 15.7013 11.8225 15.9233 11.6145 15.9841C11.5416 16.0054 11.4641 16.0046 11.3916 15.9818L2.27226 13.1099C2.03501 13.0352 1.84639 12.8498 1.76377 12.6103L0.0448891 7.6256C-0.0991528 7.20792 0.114921 6.74979 0.523017 6.60233C0.67451 6.54767 0.83877 6.54189 0.993555 6.58589Z" fill="#5287FF"/>
</g>
<defs>
<clipPath id="clip0_743_33365">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_743_33368)">
<path d="M8.0122 4C6.35375 4 4.94807 5.12419 4.51241 6.64735C4.13377 5.83944 3.31325 5.27343 2.36815 5.27343C1.06841 5.27343 0 6.34173 0 7.64133C0 8.94093 1.06841 10.0097 2.36815 10.0097C3.31325 10.0097 4.13377 9.44333 4.51241 8.63527C4.94807 10.1585 6.35375 11.2831 8.0122 11.2831C9.6584 11.2831 11.0569 10.1755 11.5037 8.6694C11.8893 9.45913 12.6997 10.0097 13.6313 10.0097C14.9311 10.0097 16 8.94093 16 7.64133C16 6.34173 14.9311 5.27343 13.6313 5.27343C12.6997 5.27343 11.8893 5.82364 11.5037 6.6132C11.0569 5.10723 9.6584 4 8.0122 4ZM8.0122 5.39C9.26413 5.39 10.2643 6.38952 10.2643 7.64133C10.2643 8.89313 9.26413 9.89313 8.0122 9.89313C6.76027 9.89313 5.76063 8.89313 5.76063 7.64133C5.76063 6.38952 6.76027 5.39 8.0122 5.39ZM2.36815 6.66344C2.91665 6.66344 3.34663 7.09287 3.34663 7.64133C3.34663 8.18973 2.91665 8.61967 2.36815 8.61967C1.81965 8.61967 1.39016 8.18973 1.39016 7.64133C1.39016 7.09287 1.81965 6.66344 2.36815 6.66344ZM13.6313 6.66344C14.1799 6.66344 14.6099 7.09287 14.6099 7.64133C14.6099 8.18973 14.1799 8.61967 13.6313 8.61967C13.0829 8.61967 12.6534 8.18973 12.6534 7.64133C12.6534 7.09287 13.0829 6.66344 13.6313 6.66344Z" fill="#0082C9"/>
</g>
<defs>
<clipPath id="clip0_743_33368">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.167772 10.1745C0.448625 10.7175 1.04755 11.1922 1.61279 11.32C1.81728 11.3662 3.29631 11.381 3.34229 11.3372C3.36027 11.3201 3.32873 11.2199 3.2722 11.1146C3.12227 10.8351 3.01425 10.3471 3.0141 9.94821C3.01362 8.8525 3.70758 7.99615 4.89652 7.62536C5.28055 7.50557 5.37046 7.45283 5.37046 7.34722C5.37046 7.19839 5.6541 6.59879 5.87654 6.2774C6.18858 5.82659 6.6017 5.48066 7.11573 5.2397C8.40254 4.63657 9.91619 4.82721 10.8437 5.70922L11.1726 6.02204L11.5331 5.93268C11.7314 5.88354 11.9585 5.84204 12.0377 5.84046C12.2193 5.83684 12.227 5.71402 12.073 5.27547C11.5911 3.90289 10.2881 3.00354 8.77613 3.00001C8.23513 2.99875 7.78277 3.09446 7.3478 3.30221C6.94482 3.49471 6.45244 3.87259 6.20878 4.17644C5.92534 4.52988 5.84727 4.63265 5.7627 4.63825C5.72434 4.64078 5.68465 4.62332 5.62383 4.60019C5.00942 4.36644 4.29975 4.32562 3.73486 4.49154C2.68928 4.79866 1.94047 5.75495 1.89573 6.84028C1.88853 7.01498 1.86616 7.18324 1.84602 7.21414C1.82588 7.24505 1.69842 7.29688 1.56277 7.32936C0.920034 7.48329 0.407782 7.87523 0.140419 8.41765C0.0135997 8.67502 0 8.75813 0 9.2764C0 9.82121 0.00845803 9.86652 0.167772 10.1745Z" fill="#094AB1"/>
<path d="M3.67823 9.89768C3.67994 10.9836 4.21935 11.7155 5.18757 11.9456C5.38888 11.9935 6.55353 12.0058 10.2175 11.9991L14.9854 11.9904L15.1999 11.8812C15.6563 11.649 15.9443 11.1812 15.9918 10.5952C16.0644 9.69927 15.664 9.0898 14.8121 8.79957L14.5138 8.69793L14.4805 8.30996C14.3588 6.89177 12.8488 6.04314 11.334 6.54166L11.021 6.64467L10.6716 6.29575C10.0364 5.66133 9.5822 5.47352 8.67182 5.46888C8.03081 5.4656 7.76326 5.52254 7.23337 5.77501C6.72706 6.01623 6.25323 6.60591 5.99732 7.31327C5.94099 7.46899 5.8949 7.64467 5.8949 7.70363C5.8949 7.89162 5.77559 7.97278 5.38833 8.04847C4.61006 8.20044 4.01862 8.61346 3.79523 9.16083C3.7041 9.38415 3.67769 9.55052 3.67823 9.89768Z" fill="#094AB1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.44095 15V1L0.5 2.43066V13.5694L8.44095 15ZM5.29189 10.4728C5.55622 10.1971 5.6884 9.80023 5.6884 9.28196C5.6884 8.95839 5.61596 8.67016 5.47108 8.41738C5.32875 8.1645 5.07585 7.91679 4.71239 7.67406C4.44297 7.49714 4.25362 7.33911 4.14433 7.20008C4.03758 7.06104 3.98421 6.89794 3.98421 6.71086C3.98421 6.52125 4.02868 6.37206 4.11764 6.26339C4.20915 6.15213 4.33877 6.09652 4.50652 6.09652C4.65902 6.09652 4.80135 6.12432 4.93352 6.17995C5.06823 6.23556 5.19658 6.29874 5.31858 6.36952L5.6617 5.54285C5.26775 5.30521 4.85727 5.18639 4.43027 5.18639C3.98293 5.18639 3.62583 5.32543 3.35895 5.60353C3.09463 5.88162 2.96245 6.25831 2.96245 6.73361C2.96245 6.98133 2.9955 7.19876 3.06158 7.38584C3.13021 7.57291 3.22552 7.74231 3.34752 7.89404C3.47206 8.04314 3.65379 8.19994 3.89271 8.36426C4.16721 8.55134 4.36418 8.72196 4.48364 8.87622C4.6031 9.02786 4.66283 9.19604 4.66283 9.38057C4.66283 9.56765 4.612 9.71552 4.51033 9.82429C4.41121 9.93296 4.26252 9.9873 4.06427 9.9873C3.71606 9.9873 3.33354 9.85202 2.9167 9.58156V10.6016C3.25729 10.7912 3.67031 10.8861 4.15577 10.8861C4.6514 10.8861 5.0301 10.7483 5.29189 10.4728Z" fill="#0072C6"/>
<path d="M9.32373 12.8355C9.58349 13.0917 9.94083 13.25 10.3354 13.25C11.1293 13.25 11.773 12.609 11.773 11.8181C11.773 11.7161 11.7622 11.6165 11.7418 11.5205C12.7264 11.1504 13.5179 10.3883 13.9243 9.42529C13.9697 9.42957 14.0159 9.43185 14.0624 9.43185C14.8564 9.43185 15.5 8.79074 15.5 8C15.5 7.20926 14.8564 6.56815 14.0624 6.56815C14.03 6.56815 13.9978 6.56929 13.9658 6.57139C13.5758 5.5657 12.7705 4.76576 11.7593 4.38008C11.7683 4.31528 11.773 4.24909 11.773 4.18182C11.773 3.39105 11.1293 2.75 10.3354 2.75C9.94083 2.75 9.58349 2.90826 9.32373 3.16452V5.19912C9.58349 5.45537 9.94083 5.61364 10.3354 5.61364C10.7543 5.61364 11.1314 5.43516 11.3941 5.15038C12.2089 5.441 12.8596 6.07475 13.1708 6.87676C12.8382 7.139 12.6249 7.54474 12.6249 8C12.6249 8.44039 12.8245 8.83431 13.1385 9.09699C12.8052 9.8865 12.1391 10.5024 11.3152 10.7705C11.0585 10.5322 10.714 10.3864 10.3354 10.3864C9.94083 10.3864 9.58349 10.5446 9.32373 10.8009V12.8355Z" fill="#0072C6"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.9 6.69268C12.4467 4.39268 10.4267 2.66602 8 2.66602C6.07333 2.66602 4.4 3.75935 3.56667 5.35935C1.56 5.57268 0 7.27268 0 9.33268C0 11.5393 1.79333 13.3327 4 13.3327H12.6667C14.5067 13.3327 16 11.8393 16 9.99935C16 8.23935 14.6333 6.81268 12.9 6.69268Z" fill="#96D1DE"/>
</svg>

After

Width:  |  Height:  |  Size: 386 B

View File

@ -0,0 +1,12 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_743_33370)">
<path d="M1.83296 7.27906L1.83635 7.2753C1.86069 7.24858 1.88526 7.22186 1.91003 7.19514C2.24212 6.81463 2.4961 6.25895 2.75067 5.70189C2.84377 5.4982 2.93693 5.29433 3.03403 5.0988C3.59247 3.98298 4.48516 3.08838 5.57602 2.55134C6.92566 1.88797 8.39933 1.86536 9.58973 2.25953C9.68285 2.29033 9.77325 2.32181 9.86253 2.35288C10.2935 2.50292 10.6978 2.64367 11.2515 2.65303C13.5884 2.48871 15.4184 3.05674 15.8443 3.98443C15.8503 3.99735 15.8557 4.01042 15.8607 4.02366C8.79997 4.92246 5.59998 6.17495 0.180055 11.7283C0.173247 11.7159 0.166863 11.7033 0.160919 11.6903C-0.333903 10.6123 0.337263 8.92307 1.83296 7.27906Z" fill="black"/>
<path d="M3.26751 11.4705C3.72741 12.4128 6.39806 12.115 9.23249 10.805C12.067 9.49453 13.9917 7.66866 13.5318 6.72588C13.0722 5.78347 10.4016 6.08177 7.56721 7.3922C4.73273 8.70221 2.80801 10.5284 3.26751 11.4705Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.67257 11.4754C5.34184 13.6037 0.904556 13.3109 0.20195 11.7804C-0.500663 10.2501 2.38561 7.1643 6.71658 5.03634C11.0476 2.90842 15.1828 2.5442 15.8854 4.07474C16.588 5.6053 14.0033 9.34779 9.67257 11.4754ZM9.21969 10.4891C7.16274 11.4996 5.22474 11.7294 4.89101 11.0024C4.55756 10.2758 5.95429 8.86717 8.01122 7.85667C10.0681 6.84592 12.0061 6.61579 12.3395 7.34273C12.6733 8.06993 11.2766 9.4783 9.21969 10.4891Z" fill="#0077FF"/>
</g>
<defs>
<clipPath id="clip0_743_33370">
<rect width="16" height="11" fill="white" transform="translate(0 2)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75736 3.75736C4.84424 2.67048 6.34287 2 8 2C11.3137 2 14 4.68629 14 8H16C16 3.58172 12.4183 0 8 0C5.79413 0 3.79519 0.894098 2.34903 2.33727L2.34682 2.33941L2.3235 2.36228C2.30404 2.38149 2.27684 2.40861 2.24255 2.44351C2.18243 2.50467 2.10045 2.58976 2 2.69795V1H0V5C0 5.55228 0.447715 6 1 6H5V4H3.52058C3.58201 3.93468 3.632 3.88303 3.66896 3.84542C3.696 3.81791 3.71606 3.79793 3.72851 3.78563L3.7414 3.77298L3.74296 3.77147L3.74328 3.77116L3.74331 3.77114L3.74343 3.77102L3.74997 3.76475L3.75736 3.75736ZM8 14C4.68629 14 2 11.3137 2 8H0C0 12.4183 3.58172 16 8 16C10.3903 16 12.535 14.9513 14 13.2915V15H16V11C16 10.4477 15.5523 10 15 10H11V12H12.4724C11.3728 13.2286 9.77618 14 8 14Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 861 B

View File

@ -70,7 +70,7 @@
"Guests": "Qonaqlar",
"Job/Title": "İş/Ad",
"LanguageAndTimeZoneSettingsDescription": "Bütün portal istifadəçiləri üçün dili dəyişin və vaxtı quraşdırın ki, portal tədbirlərinin hamısı düzgün tarix və vaxtda görünsün.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> bütün istifadəçilər üçün bütün portalın dilini dəyişməyə və saat qurşağını ayarlamağa imkan verir ki, ONLYOFFICE portalındakı olaylar düzgün tarix və vaxtla əks olunsunlar.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> bütün istifadəçilər üçün bütün portalın dilini dəyişməyə və saat qurşağını ayarlamağa imkan verir ki, {{ organizationName }} portalındakı olaylar düzgün tarix və vaxtla əks olunsunlar.",
"LanguageTimeSettingsTooltipDescription": "Təyin etdiyiniz parametrlərin qüvvəyə minməsi üçün Bölmənin altındakı <1>{{save}}</1> düyməsinin üzərinə klikləyin.<3>{{learnMore}}</3>",
"LocalFile": "Yerli fayl",
"LoginDownloadText": "Ətraflı statistikaya baxmaq üçün seçilmiş saxlama müddəti ərzində mövcud olan məlumat üçün hesabatı yükləyə bilərsiniz.",

View File

@ -68,7 +68,7 @@
"Guests": "Гости",
"Job/Title": "Работа/Заглавие",
"LanguageAndTimeZoneSettingsDescription": "Променете езика за всички потребители на портала и конфигурирайте часовата зона, за да може всички събития в портала да се показват с правилните дата и час.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> е начин да промените езика на целия портал за всички потребители на портала и да конфигурирате часовата зона, така че всички събития на портала ONLYOFFICE да се показват с правилната дата и час.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> е начин да промените езика на целия портал за всички потребители на портала и да конфигурирате часовата зона, така че всички събития на портала {{ organizationName }} да се показват с правилната дата и час.",
"LanguageTimeSettingsTooltipDescription": "За да направите въведените параметри в сила, кликнете върху бутона <1>{{save}}</1> в долната част на секцията.<3>{{learnMore}}</3>\"",
"LocalFile": "Локален файл",
"LoginDownloadText": "Можете да изтеглите отчета за наличните данни през избрания период на съхранение, за да видите подробната статистика.",

View File

@ -69,7 +69,7 @@
"Guests": "Hosté",
"Job/Title": "Pozice/Titul",
"LanguageAndTimeZoneSettingsDescription": "Změnit jazyk pro všechny uživatele portálu a nastavit časové pásmo tak, aby se všechny události portálu zobrazovaly se správným datem a časem.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> je možnost pro změnu jazyka na celém portálu pro všechny jeho uživatele a nastavení časového pásma tak, aby všechny události ONLYOFFICE portálu byly zobrazeny ve správném datu a času.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> je možnost pro změnu jazyka na celém portálu pro všechny jeho uživatele a nastavení časového pásma tak, aby všechny události {{ organizationName }} portálu byly zobrazeny ve správném datu a času.",
"LanguageTimeSettingsTooltipDescription": "Chcete-li změněné parametry aktivovat, klikněte na tlačítko <1>{{save}}</1> v dolní části.<3>{{learnMore}}</3>",
"LocalFile": "Místní soubor",
"LoginHistoryTitle": "Historie přihlášení",

View File

@ -70,7 +70,7 @@
"Guests": "Gäste",
"Job/Title": "Aufgabe/Titel",
"LanguageAndTimeZoneSettingsDescription": "Die Sprach- und Zeitzoneneinstellungen lassen Sie die Sprache des kompletten Portals für alle Benutzer ändern und die Zeitzone konfigurieren, so dass alle Ereignisse des Portals mit einem richtigen Datum und der Uhrzeit angezeigt werden.",
"LanguageTimeSettingsTooltip": "Die <0>{{text}}</0> lassen Sie die Sprache des kompletten Portals für alle Benutzer ändern und die Zeitzone konfigurieren, so dass alle Ereignisse des ONLYOFFICE-Portals mit einem richtigen Datum und der Uhrzeit angezeigt werden.",
"LanguageTimeSettingsTooltip": "Die <0>{{text}}</0> lassen Sie die Sprache des kompletten Portals für alle Benutzer ändern und die Zeitzone konfigurieren, so dass alle Ereignisse des {{ organizationName }}-Portals mit einem richtigen Datum und der Uhrzeit angezeigt werden.",
"LanguageTimeSettingsTooltipDescription": "Um die Änderungen zu übernehmen, klicken Sie auf den Button <1>{{save}}</1> im unteren Bereich der Sektion.<3>{{learnMore}}</3>",
"LocalFile": "Lokale Datei",
"LoginDownloadText": "Sie können den Bericht für die verfügbaren Daten während des ausgewählten Speicherzeitraums herunterladen, um die detaillierten Statistiken anzuzeigen.",

View File

@ -67,7 +67,7 @@
"Guests": "Επισκέπτες",
"Job/Title": "Θέση/Τίτλος εργασίας",
"LanguageAndTimeZoneSettingsDescription": "Αλλάξτε τη γλώσσα για όλους τους χρήστες της πύλης και ρυθμίστε τη ζώνη ώρας, ώστε όλα τα συμβάντα της πύλης να εμφανίζονται με τη σωστή ημερομηνία και ώρα.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>: είναι ένας τρόπος για να αλλάξετε τη γλώσσα ολόκληρης της πύλης για όλους τους χρήστες της πύλης και να ρυθμίσετε τη ζώνη ώρας, ώστε όλα τα γεγονότα της πύλης ONLYOFFICE να εμφανίζονται με τη σωστή ημερομηνία και ώρα",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>: είναι ένας τρόπος για να αλλάξετε τη γλώσσα ολόκληρης της πύλης για όλους τους χρήστες της πύλης και να ρυθμίσετε τη ζώνη ώρας, ώστε όλα τα γεγονότα της πύλης {{ organizationName }} να εμφανίζονται με τη σωστή ημερομηνία και ώρα",
"LanguageTimeSettingsTooltipDescription": "Για να τεθούν σε ισχύ οι παράμετροι που ορίσατε κάντε κλικ στο κουμπί <1>{{save}}</1> στο κάτω μέρος της ενότητας.<3>{{{learnMore}}</3>",
"LocalFile": "Τοπικό αρχείο",
"LogoDocsEditor": "Λογότυπο για την επικεφαλίδα των προγραμμάτων επεξεργασίας",

View File

@ -1,9 +1,10 @@
{
"AboutCompanyAddressTitle": "address",
"AboutCompanyEmailTitle": "email",
"AboutCompanyAddressTitle": "Address",
"AboutCompanyEmailTitle": "E-mail",
"AboutCompanyTelTitle": "tel.",
"AboutHeader": "About this program",
"DocumentManagement": "Document management",
"OnlineEditors": "Online editors",
"Site": "Site",
"SoftwareLicense": "Software license"
}

View File

@ -19,9 +19,15 @@
"LoginRegistryButton": "Join",
"PassworResetTitle": "Now you can create a new password.",
"PhoneSubtitle": "The two-factor authentication is enabled to provide additional portal security. Enter your mobile phone number to continue work on the portal. Mobile phone number must be entered using an international format with country code.",
"PortalContinueTitle": "Please confirm that you want to reactivate your portal",
"PortalRemoveTitle": "Please confirm that you want to delete your portal",
"PortalDeactivateTitle": "Please confirm that you want to deactivate your portal",
"Reactivate": "Reactivate",
"SetAppButton": "Connect app",
"SetAppDescription": "Two-factor authentication is enabled. Configure your authenticator app to continue work on the portal. You can use Google Authenticator for <1>Android</1> and <4>iOS</4> or Authenticator for <8>Windows Phone</8>.",
"SetAppInstallDescription": "To connect the app, scan the QR code or manually enter your secret key <1>{{ secretKey }}</1>, and then enter a 6-digit code from your app in the field below.",
"SetAppTitle": "Configure your authenticator application",
"SuccessDeactivate": "Your account has been successfully deactivated. In 10 seconds you will be redirected to the <1>site</1>",
"SuccessReactivate": "Your account has been successfully reactivated. In 10 seconds you will be redirected to the <1>portal</1>",
"WelcomeUser": "Welcome to join our portal! To get started register, or log in via social networking."
}

View File

@ -4,5 +4,6 @@
"ConnectMakeShared": "Share and put into 'Common' folder",
"ConnectionUrl": "Connection url",
"Login": "Login",
"Reconnect": "Reconnect"
"Reconnect": "Reconnect",
"SuccessfulConnectionOfAThirdParty": "Connection of a third-party resource was successful."
}

View File

@ -20,6 +20,7 @@
"ReviewRoomDescription": "Request a review or comments on the documents",
"ReviewRoomTitle": "Review room",
"RoomEditing": "Room editing",
"RootLabel": "Root",
"TagsPlaceholder": "Add a tag",
"ThirdPartyStorageComboBoxPlaceholder": "Select storage",
"ThirdPartyStorageDescription": "Use third-party services as data storage for this room. A new folder for storing this rooms data will be created in the connected storage",

View File

@ -1,6 +1,8 @@
{
"DeleteForeverButton": "Delete forever",
"DeleteForeverNote": "All items from Trash will be deleted forever. You wont be able to restore them.",
"DeleteForeverNoteArchive": "All items from Archived will be deleted forever. You wont be able to restore them.",
"DeleteForeverTitle": "Delete forever?",
"SuccessEmptyTrash": "Trash emptied"
"SuccessEmptyTrash": "Trash emptied",
"SuccessEmptyArchived": "Archived emptied"
}

View File

@ -3,5 +3,8 @@
"Error403Text": "Sorry, access denied.",
"Error404Text": "Sorry, the resource cannot be found.",
"ErrorEmptyResponse": "Empty response",
"ErrorOfflineText": "No internet connection found."
"ErrorInvalidHeader": "Incorrect email or expired link",
"ErrorInvalidText": "In 10 seconds you will be redirected to the <1>login page</1>",
"ErrorOfflineText": "No internet connection found.",
"ErrorUnavailableText": "Portal unavailable"
}

View File

@ -1,5 +1,9 @@
{
"All": "All",
"Archived": "Archived",
"ArchiveAction": "Empty archive",
"ArchivedRoomAction": "The room '{{name}}' is archived",
"ArchivedRoomsAction": "The rooms are archived",
"AllFiles": "All files",
"Archives": "Archives",
"ArchiveEmptyScreen": "You can archive rooms you dont use and restore them in your DocSpace at any moment or delete them permanently. These rooms will appear here.",
@ -89,6 +93,7 @@
"RoomRemoved": "Room removed",
"RoomsRemoved": "Rooms removed",
"RestoreAll": "Restore all",
"RestoreAllArchive": "Are you sure you want to restore all rooms?",
"SearchByContent": "Search by file contents",
"SendByEmail": "Send by email",
"Share": "Share",
@ -96,11 +101,12 @@
"ShowVersionHistory": "Show version history",
"Spreadsheet": "Spreadsheet",
"Tags": "Tags",
"ToArchive": "Move to archive",
"TooltipElementCopyMessage": "Copy {{element}}",
"TooltipElementsCopyMessage": "Copy {{element}} elements",
"TooltipElementsMoveMessage": "Move {{element}} elements",
"TrashEmptyDescription": "All deleted files are moved to 'Trash'. Restore files deleted by mistake or delete them permanently. Please note, that the files deleted from the 'Trash' cannot be restored any longer.",
"UnarchivedRoomAction": "The room '{{name}}' is unarchived",
"UnarchivedRoomsAction": "The rooms are unarchived",
"UnblockVersion": "Unblock/Check-in",
"Unpin": "Unpin",
"UploadToFolder": "Upload to folder",

View File

@ -14,6 +14,7 @@
"Properties": "Properties",
"Data": "Data",
"StorageType": "Storage type",
"FileExtension": "File extension",
"DateModified": "Date modified",
"LastModifiedBy": "Last modified by",

View File

@ -0,0 +1,10 @@
{
"ClickHere": "click here",
"ConfirmEmailHeader": "Please activate your email to get access to all the portal features.",
"ConfirmEmailDescription": "Use the link provided in the activation email. Haven't received an email with the activation link?",
"RequestActivation": "Request activation once again",
"RoomQuotaHeader": "Rooms is about to be exceeded: {{currentValue}} / {{maxValue}}",
"RoomQuotaDescription": "You can archived the unnecessary rooms or <1>{{clickHere}}</1> to find a better pricing plan for your portal.",
"StorageQuotaHeader": "Storage space amount is about to be exceeded: {{currentValue}} / {{maxValue}}",
"StorageQuotaDescription": "You can remove the unnecessary files or <1>{{clickHere}}</1> to find a better pricing plan for your portal."
}

View File

@ -16,7 +16,8 @@
"DowngradeNow": "Downgrade now",
"FreeStartupPlan": "Free {{planName}} plan",
"GracePeriodActivated": "Grace period activated",
"GracePeriodActivatedDescription": "Grace period is effective from <1>{{fromDate}}</1> to <1>{{byDate}}</1> ({{delayDaysCount}}). During the grace period, admins cannot create new rooms and add new users. After the due date of the grace period, DocSpace will become unavailable until the payment is made.",
"GracePeriodActivatedInfo": "Grace period is effective <1>from {{fromDate}} to {{byDate}}</1> ({{delayDaysCount}}).",
"GracePeriodActivatedDescription": "During the grace period, admins cannot create new rooms and add new users. After the due date of the grace period, DocSpace will become unavailable until the payment is made.",
"InvalidEmail": "Invalid email",
"LatePayment": "Late payment",
"ManagerTypesDescription": "Admin account types and their privileges",
@ -38,5 +39,10 @@
"TotalPricePerMonth": "<1>{{currencySymbol}}</1><2>{{price}}</2><3>/month</3>",
"UpgradeNow": "Upgrade now",
"UserNotFound": "User <1>«{{email}}»</1> is not found",
"YourPrice": "Your price"
"YourPrice": "Your price",
"PaymentOverdue": "Cannot add new users.",
"BusinessPlanPaymentOverdue": "Cannot add new users. Business plan payment overdue",
"UpgradePlan": "Upgrade plan",
"UpgradePlanInfo": "Adding new users will exceed the maximum number of room members allowed by your current pricing plan.",
"ChooseNewPlan": "Would you like to choose a new pricing plan?"
}

View File

@ -8,6 +8,7 @@
"EditPhoto": "Edit photo",
"EditSubscriptionsBtn": "Edit subscriptions",
"EditUser": "Edit profile",
"EmailNotVerified": "Email not verified",
"InterfaceTheme": "Interface theme",
"InviteAgainLbl": "Invite again",
"LightTheme": "Light theme",
@ -17,6 +18,7 @@
"PhoneLbl": "Phone",
"ProviderSuccessfullyConnected": "Provider successfully connected",
"ProviderSuccessfullyDisconnected": "Provider successfully disconnected",
"SendAgain": "Send again",
"ShowBackupCodes": "Show backup codes",
"SubscriptionEmailTipsToggleLbl": "Email notification with tips and tricks",
"SubscriptionTurnOffToast": "You have been successfully unsubscribed from the the mailing list. <1>Subscribe again</1>",

View File

@ -45,10 +45,11 @@
"BackupList": "Backup List",
"BackupListWarningText": "If you delete any items from the list, their corresponding files will also be deleted. This action cannot be undone. To delete all the files use the link:",
"Branding": "Branding",
"BrandingSectionDescription": "Specify your company information, add links to external resources, and email addresses displayed within the online office interface.",
"BrandingSubtitle": "Use this option to provide on-brand experience to your users. These settings will be effective for all of your portals.",
"BrowserNoCanvasSupport": "Your browser does not support the HTML5 canvas tag.",
"BreakpointWarningText": "This section is only available in desktop version",
"BreakpointWarningTextPrompt": "Please use the desktop site to access",
"BreakpointWarningTextPrompt": "Please use the desktop site to access <1>{{content}}</1>",
"ByApp": "By authenticator app",
"BySms": "By sms",
"ChangeLogoButton": "Change Logo",
@ -58,7 +59,9 @@
"ClearBackupList": "Delete all backups",
"CompanyInfoSettings": "Company info settings",
"CompanyNameForCanvasLogo": "Company name",
"CompanyInfoSettingsDescription": "This information will be displayed in the <1>{{link}}</1> window.",
"ConfirmEmailSended": "Confirmation e-mail has been sent to {{ownerName}}",
"PortalDeletionEmailSended": "A link to confirm the operation has been sent to {{ownerEmail}} (the email address of the portal owner).",
"CustomDomains": "Custom domains",
"CustomTitles": "Custom titles",
"CustomTitlesFrom": "From",
@ -69,13 +72,17 @@
"CustomTitlesWelcome": "Welcome Page Settings",
"Customization": "Customization",
"CustomizationDescription": "This subsection allows you to change the look and feel of your portal. You can use your own company logo, name and text to match your organization brand.",
"DataBackup": "Data backup",
"Deactivate": "Deactivate",
"DeactivateOrDeletePortal": "Deactivate or delete portal.",
"DeleteDataHeader": "Portal deactivation/deletion",
"DeleteDocSpace": "Delete DocSpace",
"DeleteDocSpaceInfo": "Before you delete the portal, please make sure that automatic billing is turned off. You may check the status of automatic billing in <1>on your Stripe customer portal.</1>",
"Disabled": "Disabled",
"DNSSettings": "DNS Settings",
"DNSSettingsDescription": "DNS Settings is a way to set an alternative URL for your portal.",
"DNSSettingsMobile": "Send your request to our support team, and our specialists will help you with the settings.",
"DNSSettingsTooltip": "DNS Settings allow you to set an alternative URL address for your ONLYOFFICE portal. Send your request to our support team, and our specialists will help you with the settings.<2>{{learnMore}}</2>",
"DataBackup": "Data backup",
"DeactivateOrDeletePortal": "Deactivate or delete portal.",
"Disabled": "Disabled",
"DocSpaceMenu": "DocSpace menu",
"DocumentsAdministratorsCan": "Documents administrators can link Dropbox, Box, and other accounts to Common Documents and set up access rights in this section",
"DownloadCopy": "Download the copy",
@ -104,7 +111,7 @@
"IPSecurityWarningHelper": "First you need to specify your current IP or the IP range your current IP address belongs to, otherwise your portal access will be blocked right after you save the settings. The portal owner will have the portal access from any IP address.",
"Job/Title": "Job/Title",
"LanguageAndTimeZoneSettingsDescription": "Language and Time Zone Settings is a way to change the language of the whole portal for all portal users and to configure the time zone so that all the events of the portal will be shown with the correct date and time.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> is a way to change the language of the whole portal for all portal users and to configure the time zone so that all the events of the ONLYOFFICE portal will be shown with the correct date and time.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> is a way to change the language of the whole portal for all portal users and to configure the time zone so that all the events of the {{ organizationName }} portal will be shown with the correct date and time.",
"LanguageTimeSettingsTooltipDescription": "To make the parameters you set take effect click the <1>{{save}}</1> button at the bottom of the section.<3>{{learnMore}}</3>",
"Lifetime": "Lifetime (min)",
"LocalFile": "Local file",
@ -146,6 +153,12 @@
"PortalNameEmpty": "Account name is empty",
"PortalNameIncorrect": "Incorrect account name",
"PortalNameLength": "The account name must be between 6 and 50 characters long",
"PortalDeactivation": "Deactivate DocSpace",
"PortalDeactivationDescription": "Use this option to deactivate your portal temporarily.",
"PortalDeactivationHelper": "If you wish to deactivate the portal, your portal and all information associated with it will be blocked so that no one has access to it for a particular period. To do that click the Deactivate button. A link to confirm the operation will be sent to the email address of the portal owner.\n In case you want to come back to the portal and resume using it you will need to use the second link provided in the confirmation email. So, please, keep this email in a safe place.",
"PortalDeletion": "Portal Deletion",
"PortalDeletionDescription": "Use this option to delete your portal permanently.",
"PortalDeletionHelper": "If you do not think you will use the portal and would like to delete your portal permanently submit your request using the Delete button. Please, keep in mind that you will not be able to reactivate your portal or recover any information associated with it.",
"PortalOwner": "Portal Owner",
"PortalRenaming": "Portal Renaming",
"PortalRenamingDescription": "Here you can change your portal address.",
@ -161,13 +174,14 @@
"RestoreBackupHelpNote": "Select the storage where the data is saved, enter necessary details and check the <strong>Send notification to portal users</strong> to alert your portal users about the backup/restore operations.",
"RestoreBackupResetInfoWarningText": "All current passwords will be reset. Portal users will get an email with the access restoration link.",
"RestoreBackupWarningText": "The portal will become unavailable during the restore process. After the restore is complete all the changes made after the date of the selected restore point will be lost.",
"RestoreDefaultButton": "Restore to Default",
"RestoreDefaultButton": "Restore to default",
"RoomsModule": "Backup room",
"RoomsModuleDescription": "You may create a new room specifically for the backup, choose one of the existing rooms, or save the copy in their {{roomName}} room.",
"SelectFileInGZFormat": "Select the file in .GZ format",
"SendNotificationAboutRestoring": "Send notification about portal restoring to users",
"ServerSideEncryptionMethod": "Server Side Encryption Method",
"ServiceUrl": "Service Url",
"SingleSignOn": "Single Sign-On",
"SessionLifetime": "Session Lifetime",
"SessionLifetimeDescription": "Session Lifetime allows to set time (in minutes) before the portal users will need to enter the portal credentials again in order to access the portal.",
"SessionLifetimeHelper": "After save all the users will be logged out from portal.",
@ -179,7 +193,6 @@
"ShowSampleDocuments": "Show sample documents in new rooms",
"ShowVideoGuides": "Show link to Video Guides",
"ShowHelpCenter": "Show link to Help Center",
"SingleSignOn": "Single Sign-On",
"StoragePeriod": "Storage period",
"StudioTimeLanguageSettings": "Language and Time Zone Settings",
"SuccessfullySaveGreetingSettingsMessage": "Welcome Page settings have been successfully saved",
@ -190,7 +203,6 @@
"Template": "Template",
"TemporaryStorage": "Temporary storage",
"TemporaryStorageDescription": "Backup is stored in the 'Backup' section, you will be able to download it within 24 hours after creating.",
"TheAppearanceSettings": "the Appearance settings",
"ThirdPartyAuthorization": "Third-party Authorization",
"ThirdPartyBodyDescription": "Detailed instructions in our <2>Help Center</2>.",
"ThirdPartyBottomDescription": "Need help? Contact our <2>Support Team.</2>",

View File

@ -70,7 +70,7 @@
"Guests": "Invitados",
"Job/Title": "Posición/Título",
"LanguageAndTimeZoneSettingsDescription": "Cambie el idioma para todos los usuarios del portal y configure la zona horaria para que todos los eventos del portal se muestren con la fecha y hora correctas.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> es un modo para cambiar el idioma del portal para todos los usuarios del portal y para configurar la zona horaria para que todos los eventos del portal ONLYOFFICE se muestren con la fecha y hora correctas.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> es un modo para cambiar el idioma del portal para todos los usuarios del portal y para configurar la zona horaria para que todos los eventos del portal {{ organizationName }} se muestren con la fecha y hora correctas.",
"LanguageTimeSettingsTooltipDescription": "Para activar los parámetros ingresados pulse <1>{{save}}</1> en la parte inferior de la sección.<3>{{learnMore}}</3>",
"LocalFile": "Archivo local",
"LoginDownloadText": "Usted puede descargar el informe para los datos disponibles durante el período de almacenamiento seleccionado para ver estadísticas detalladas.",

View File

@ -69,7 +69,7 @@
"Guests": "Vieraat",
"Job/Title": "Työ/Titteli",
"LanguageAndTimeZoneSettingsDescription": "Vaihda kaikkien portaalin käyttäjien kieli ja määritä aikavyöhyke siten, että kaikki portaalitapahtumat näytetään oikealla päivämäärällä ja kellonajalla.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> voidaan vaihtaa koko sivuston kieli kaikille käyttäjille ja määrittää aikavyöhyke siten, että kaikki ONLYOFFICE tapahtumat näytetään oikealla päivämäärällä ja ajalla.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> voidaan vaihtaa koko sivuston kieli kaikille käyttäjille ja määrittää aikavyöhyke siten, että kaikki {{ organizationName }} tapahtumat näytetään oikealla päivämäärällä ja ajalla.",
"LanguageTimeSettingsTooltipDescription": "Avaa alasvetovalikko määrittääksesi tarpeelliset parametrit. Ota tekemäsi asetukset käyttöön klikkaamalla <1>{{save}}</1> painiketta.<3>{{learnMore}}</3>",
"LocalFile": "Paikallinen tiedosto",
"LoginHistoryTitle": "Kirjautumishistoria",

View File

@ -70,7 +70,7 @@
"Guests": "Invités",
"Job/Title": "Emploi/Titre",
"LanguageAndTimeZoneSettingsDescription": "Les paramètres de langue et fuseau horaire est un moyen de changer la langue du portail pour tous les utilisateurs et de configurer le fuseau horaire afin que tous les événements du portail seront affichés avec la date et l'heure correctes.",
"LanguageTimeSettingsTooltip": "Les <0>{{text}}</0> est un moyen de changer la langue du portail pour tous les utilisateurs et de configurer le fuseau horaire afin que tous les événements du portail ONLYOFFICE seront affichés avec la date et l'heure correctes.",
"LanguageTimeSettingsTooltip": "Les <0>{{text}}</0> est un moyen de changer la langue du portail pour tous les utilisateurs et de configurer le fuseau horaire afin que tous les événements du portail {{ organizationName }} seront affichés avec la date et l'heure correctes.",
"LanguageTimeSettingsTooltipDescription": "Pour valider les changements effectués, utilisez le bouton <1>{{save}}</1> en bas de la section.<3>{{learnMore}}</3>",
"LocalFile": "Fichier local",
"LoginDownloadText": "Vous pouvez télécharger un rapport des données accessibles pour la période de stockage sélectionnée pour voir les statistiques détaillées. ",

View File

@ -67,7 +67,7 @@
"Guests": "Հյուրեր",
"Job/Title": "Աշխատանք/Անվանում",
"LanguageAndTimeZoneSettingsDescription": "Լեզվի և ժամային գոտու կարգավորումները կայքէջի բոլոր օգտագործողների համար ամբողջ կայքէջի լեզուն փոխելու և ժամային գոտին այնպես կարգավորելու միջոց է, որպեսզի կայքէջի բոլոր իրադարձությունները ցուցադրվեն ճիշտ ամսաթվով և ժամով:",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>կայքէջի բոլոր օգտագործողների համար ամբողջ կայքէջի լեզուն փոխելու և ժամային գոտին այնպես կարգավորելու միջոց է, որպեսզի ONLYOFFICE կայքէջի բոլոր իրադարձությունները ցուցադրվեն ճիշտ ամսաթվով և ժամով:",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>կայքէջի բոլոր օգտագործողների համար ամբողջ կայքէջի լեզուն փոխելու և ժամային գոտին այնպես կարգավորելու միջոց է, որպեսզի {{ organizationName }} կայքէջի բոլոր իրադարձությունները ցուցադրվեն ճիշտ ամսաթվով և ժամով:",
"LanguageTimeSettingsTooltipDescription": "Ձեր սահմանած պարամետրերը ուժի մեջ մտնելու համար սեղմեք կոճակը<1>{{save}}</1> կոճակը հատվածի ներքևում:<3>{{learnMore}}</3>",
"LocalFile": "Տեղական ֆայլ",
"LogoDocsEditor": "Էջագլխի խմբագրիչների լոգո",

View File

@ -70,7 +70,7 @@
"Guests": "Ospiti",
"Job/Title": "Occupazione/Titolo",
"LanguageAndTimeZoneSettingsDescription": "Impostazioni di lingua e fuso orario ti permettono di cambiare la lingua di tutto il portale per tutti gli utenti e configurare il fuso orario perché tutti gli eventi del portale siano visualizzati con la data e l'ora corretta.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ti permettono di cambiare la lingua di tutto il portale per tutti gli utenti e configurare il fuso orario perché tutti gli eventi del portale ONLYOFFICE siano visualizzati con la data e l'ora corretta.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ti permettono di cambiare la lingua di tutto il portale per tutti gli utenti e configurare il fuso orario perché tutti gli eventi del portale {{ organizationName }} siano visualizzati con la data e l'ora corretta.",
"LanguageTimeSettingsTooltipDescription": "Per applicare i parametri impostati clicca su <1>{{save}}</1> nella parte inferiore della sezione.<3>{{learnMore}}</3>",
"LocalFile": "File locale",
"LoginDownloadText": "È possibile scaricare il report per i dati disponibili durante il periodo di archiviazione selezionato per visualizzare le statistiche dettagliate.",

View File

@ -69,7 +69,7 @@
"Guests": "お客様",
"Job/Title": "職務/役職",
"LanguageAndTimeZoneSettingsDescription": "すべてのポータルユーザーの言語を変更し、タイムゾーンを設定して、すべてのポータルイベントが正しい日付と時間で表示されるようにします。",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>は、ONLYOFFICEポータルのすべてのイベントが正しい日付と時刻で表示されるように、ポータル全体の言語を全員のユーザーに変更、タイムゾーンを設定する方法です。",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>は、{{ organizationName }}ポータルのすべてのイベントが正しい日付と時刻で表示されるように、ポータル全体の言語を全員のユーザーに変更、タイムゾーンを設定する方法です。",
"LanguageTimeSettingsTooltipDescription": "設定されたパラメータを有効にするため、セクションの下にある<1>{{save}}</1>ボタンをクリックしてください。<3>{{learnMore}}</3>",
"LocalFile": "ローカルファイル",
"LoginHistoryTitle": "ログイン履歴",

View File

@ -67,7 +67,7 @@
"Guests": "게스트",
"Job/Title": "직책",
"LanguageAndTimeZoneSettingsDescription": "모든 포털 사용자에 대해 언어를 변경하고 시간대를 설정하여 모든 포털 이벤트의 정확한 날짜와 시간이 표시되도록 하세요.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>은 모든 포털 사용자에 대해 전체 포털의 언어를 변경하고 ONLYOFFICE 포털의 모든 이벤트가 올바른 날짜 및 시각으로 표시되도록 시간대를 구성하는 방법입니다.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0>은 모든 포털 사용자에 대해 전체 포털의 언어를 변경하고 {{ organizationName }} 포털의 모든 이벤트가 올바른 날짜 및 시각으로 표시되도록 시간대를 구성하는 방법입니다.",
"LanguageTimeSettingsTooltipDescription": "설정한 매개변수를 적용하려면, 섹션 하단의 <1>{{save}}</1> 버큰을 클릭하세요.<3>{{learnMore}}</3>",
"LocalFile": "로컬 파일",
"LogoDocsEditor": "편집기 헤더 로고",

View File

@ -65,7 +65,7 @@
"Guests": "ແຂກ",
"Job/Title": "ວຽກ/ຕຳແໜ່ງ",
"LanguageAndTimeZoneSettingsDescription": "ປ່ຽນພາສາສຳລັບຜູ້ໃຊ້ portal ທັງຫມົດລະກຳນົດເຂດເວລາເພື່ອໃຫ້ກິດຈະກຳຂອງ portal ທົງຫມົດຈະສະແດງວັນທີແລະເວລາທີ່ຖືກຕ້ອງ",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ແມ່ນວິທີທີ່ຈະປ່ຽນພາສາຂອງປະຕູທັງໝົດສຳລັບຜູ້ໃຊ້ປະຕູທັງໝົດ ແລະກຳນົດເຂດເວລາເພື່ອໃຫ້ເຫດການທັງໝົດຂອງ ປະຕູ ONLYOFFICE ຈະຖືກສະແດງດ້ວຍວັນທີທີ່ຖືກຕ້ອງ. ແລະເວລາ.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ແມ່ນວິທີທີ່ຈະປ່ຽນພາສາຂອງປະຕູທັງໝົດສຳລັບຜູ້ໃຊ້ປະຕູທັງໝົດ ແລະກຳນົດເຂດເວລາເພື່ອໃຫ້ເຫດການທັງໝົດຂອງ ປະຕູ {{ organizationName }} ຈະຖືກສະແດງດ້ວຍວັນທີທີ່ຖືກຕ້ອງ. ແລະເວລາ.",
"LanguageTimeSettingsTooltipDescription": "ເພື່ອເຮັດໃຫ້ພາລາມິເຕີທີ່ທ່ານຕັ້ງມີຜົນບັງຄັບໃຊ້, ໃຫ້ຄລິກໃສ່ປຸ່ມ <1>{{save}}</1> ຢູ່ລຸ່ມສຸດຂອງພາກສ່ວນ.<3>{{ learnMore }}</3>",
"LocalFile": "ທ້ອງຖິ່ນ ໄຟລ",
"LogoDocsEditor": "ໂລໂກສຳລັບແກ້ໄຂສ່ວນຫົວ",

View File

@ -69,7 +69,7 @@
"Guests": "Viesi",
"Job/Title": "Darbs/amata nosaukums",
"LanguageAndTimeZoneSettingsDescription": "Mainiet valodu visiem portāla lietotājiem un konfigurējiet laika joslu tā, lai visi portāla notikumi tiktu parādīti ar pareizu datumu un laiku.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ir veids, kā mainīt portāla valodu visiem portāla lietotājiem un konfigurētu laika joslu, lai ONLYOFFICE portāla notikumi tiks rādīti ar pareizu datumu un laiku.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> ir veids, kā mainīt portāla valodu visiem portāla lietotājiem un konfigurētu laika joslu, lai {{ organizationName }} portāla notikumi tiks rādīti ar pareizu datumu un laiku.",
"LanguageTimeSettingsTooltipDescription": "Atveriet atbilstošo nolaižamos sarakstu, lai iestatītu nepieciešamos parametrus. Lai lietotu tos izmaiņas izmantojiet pogu <1>{{save}}</1> sadaļas apakšējā daļā.<3>{{learnMore}}</3>",
"LocalFile": "Vietējais fails",
"LoginHistoryTitle": "Pieteikšanās vēsture",

View File

@ -69,7 +69,7 @@
"Guests": "Gasten",
"Job/Title": "Functie/Titel",
"LanguageAndTimeZoneSettingsDescription": "Wijzig de taal voor alle portaalgebruikers en configureer de tijdzone, zodat alle portaalgebeurtenissen met de juiste datum en tijd worden weergegeven.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> is een manier om de taal van het hele portaal voor alle portaalgebruikers te wijzigen en de tijdzone te configureren zodat alle gebeurtenissen van het ONLYOFFICE portaal met de juiste datum en tijd worden weergegeven.",
"LanguageTimeSettingsTooltip": "<0>{{text}}</0> is een manier om de taal van het hele portaal voor alle portaalgebruikers te wijzigen en de tijdzone te configureren zodat alle gebeurtenissen van het {{ organizationName }} portaal met de juiste datum en tijd worden weergegeven.",
"LanguageTimeSettingsTooltipDescription": "Als u de parameters die u instelt in werking wilt laten treden, klikt u op de knop <1>{{save}}</1> onderaan.<3>{{learnMore}}</3>",
"LocalFile": "Lokaal bestand",
"LoginHistoryTitle": "Inloggeschiedenis",

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