Merge branch 'develop' into feature/webhooks-ui
This commit is contained in:
commit
913b931544
@ -12,4 +12,4 @@ Write-Host "Run Document server" -ForegroundColor Green
|
||||
$DOCUMENT_SERVER_IMAGE_NAME = "onlyoffice/documentserver-de:latest"
|
||||
|
||||
|
||||
docker run -i -t -d -p 8085:80 -e JWT_ENABLED=false -e JWT_IN_BODY=false --restart=always -v $RootDir/Data:/var/www/onlyoffice/Data $DOCUMENT_SERVER_IMAGE_NAME
|
||||
docker run -i -t -d -p 8085:80 -e JWT_ENABLED=true -e JWT_SECRET=secret -e JWT_HEADER=AuthorizationJwt --restart=always -v $RootDir/Data:/var/www/onlyoffice/Data $DOCUMENT_SERVER_IMAGE_NAME
|
@ -186,7 +186,7 @@ WORKDIR ${BUILD_PATH}/services/ASC.Data.Backup.BackgroundTasks/
|
||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
||||
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Data.Backup.BackgroundTasks/service/ .
|
||||
|
||||
CMD ["ASC.Data.Backup.BackgroundTasks.dll", "ASC.Data.Backup.BackgroundTasks"]
|
||||
CMD ["ASC.Data.Backup.BackgroundTasks.dll", "ASC.Data.Backup.BackgroundTasks", "core:eventBus:subscriptionClientName=asc_event_bus_backup_queue"]
|
||||
|
||||
# ASC.ApiSystem ##
|
||||
FROM dotnetrun AS api_system
|
||||
@ -231,7 +231,7 @@ WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
|
||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
||||
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Files.Service/service/ .
|
||||
|
||||
CMD ["ASC.Files.Service.dll", "ASC.Files.Service"]
|
||||
CMD ["ASC.Files.Service.dll", "ASC.Files.Service", "core:eventBus:subscriptionClientName=asc_event_bus_files_service_queue"]
|
||||
|
||||
## ASC.Notify ##
|
||||
FROM dotnetrun AS notify
|
||||
@ -240,7 +240,7 @@ WORKDIR ${BUILD_PATH}/services/ASC.Notify/service
|
||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
||||
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Notify/service/ .
|
||||
|
||||
CMD ["ASC.Notify.dll", "ASC.Notify"]
|
||||
CMD ["ASC.Notify.dll", "ASC.Notify", "core:eventBus:subscriptionClientName=asc_event_bus_notify_queue"]
|
||||
|
||||
## ASC.People ##
|
||||
FROM dotnetrun AS people_server
|
||||
|
@ -38,8 +38,9 @@ ELK_PORT = os.environ["ELK_PORT"] if environ.get("ELK_PORT") else "9200"
|
||||
ELK_THREADS = os.environ["ELK_THREADS"] if environ.get("ELK_THREADS") else "1"
|
||||
|
||||
KAFKA_HOST = os.environ["KAFKA_HOST"] if environ.get("KAFKA_HOST") else "kafka:9092"
|
||||
RUN_FILE = sys.argv[1] if sys.argv[1] else "none"
|
||||
LOG_FILE = sys.argv[2] if sys.argv[2] else "none"
|
||||
RUN_FILE = sys.argv[1] if (len(sys.argv) > 1) else "none"
|
||||
LOG_FILE = sys.argv[2] if (len(sys.argv) > 2) else "none"
|
||||
CORE_EVENT_BUS = sys.argv[3] if (len(sys.argv) > 3) else ""
|
||||
|
||||
REDIS_HOST = os.environ["REDIS_HOST"] if environ.get("REDIS_HOST") else "onlyoffice-redis"
|
||||
REDIS_PORT = os.environ["REDIS_PORT"] if environ.get("REDIS_PORT") else "6379"
|
||||
@ -84,7 +85,8 @@ class RunServices:
|
||||
" --log:dir=" + LOG_DIR +\
|
||||
" --log:name=" + LOG_FILE +\
|
||||
" core:products:folder=/var/www/products/" +\
|
||||
" core:products:subfolder=server")
|
||||
" core:products:subfolder=server" + " " +\
|
||||
CORE_EVENT_BUS)
|
||||
else:
|
||||
os.system("dotnet " + RUN_FILE + " --urls=" + URLS + self.SERVICE_PORT +\
|
||||
" --\'$STORAGE_ROOT\'=" + APP_STORAGE_ROOT +\
|
||||
@ -93,7 +95,8 @@ class RunServices:
|
||||
" --log:name=" + LOG_FILE +\
|
||||
" --ENVIRONMENT=" + ENV_EXTENSION +\
|
||||
" core:products:folder=/var/www/products/" +\
|
||||
" core:products:subfolder=server")
|
||||
" core:products:subfolder=server" + " " +\
|
||||
CORE_EVENT_BUS)
|
||||
|
||||
def openJsonFile(filePath):
|
||||
try:
|
||||
|
@ -57,13 +57,13 @@ public class LdapNotifyService : BackgroundService
|
||||
{
|
||||
var tId = t.Id;
|
||||
|
||||
var ldapSettings = settingsManager.LoadForTenant<LdapSettings>(tId);
|
||||
var ldapSettings = settingsManager.Load<LdapSettings>(tId);
|
||||
if (!ldapSettings.EnableLdapAuthentication)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cronSettings = settingsManager.LoadForTenant<LdapCronSettings>(tId);
|
||||
var cronSettings = settingsManager.Load<LdapCronSettings>(tId);
|
||||
if (string.IsNullOrEmpty(cronSettings.Cron))
|
||||
{
|
||||
continue;
|
||||
@ -103,13 +103,13 @@ public class LdapNotifyService : BackgroundService
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var settingsManager = scope.ServiceProvider.GetRequiredService<SettingsManager>();
|
||||
var ldapSettings = settingsManager.LoadForTenant<LdapSettings>(tenant.Id);
|
||||
var ldapSettings = settingsManager.Load<LdapSettings>(tenant.Id);
|
||||
|
||||
if (!ldapSettings.EnableLdapAuthentication)
|
||||
{
|
||||
var cronSettings = settingsManager.LoadForTenant<LdapCronSettings>(tenant.Id);
|
||||
var cronSettings = settingsManager.Load<LdapCronSettings>(tenant.Id);
|
||||
cronSettings.Cron = "";
|
||||
settingsManager.SaveForTenant(cronSettings, tenant.Id);
|
||||
settingsManager.Save(cronSettings, tenant.Id);
|
||||
UnregisterAutoSync(tenant);
|
||||
return;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ public class LdapUserManager
|
||||
var quotaSettings = _settingsManager.Load<TenantUserQuotaSettings>();
|
||||
if (quotaSettings.EnableUserQuota)
|
||||
{
|
||||
_settingsManager.SaveForUser(new UserQuotaSettings { UserQuota = ldapUserInfo.LdapQouta }, ldapUserInfo.Id);
|
||||
_settingsManager.Save(new UserQuotaSettings { UserQuota = ldapUserInfo.LdapQouta }, ldapUserInfo.Id);
|
||||
}
|
||||
|
||||
|
||||
|
@ -64,25 +64,26 @@ public abstract class BaseStartup
|
||||
|
||||
public virtual void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddCustomHealthCheck(_configuration);
|
||||
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.AddBaseDbContextPool<AccountLinkContext>()
|
||||
.AddBaseDbContextPool<CoreDbContext>()
|
||||
.AddBaseDbContextPool<TenantDbContext>()
|
||||
.AddBaseDbContextPool<UserDbContext>()
|
||||
.AddBaseDbContextPool<TelegramDbContext>()
|
||||
.AddBaseDbContextPool<FirebaseDbContext>()
|
||||
.AddBaseDbContextPool<CustomDbContext>()
|
||||
.AddBaseDbContextPool<WebstudioDbContext>()
|
||||
.AddBaseDbContextPool<InstanceRegistrationContext>()
|
||||
.AddBaseDbContextPool<IntegrationEventLogContext>()
|
||||
.AddBaseDbContextPool<FeedDbContext>()
|
||||
.AddBaseDbContextPool<MessagesContext>()
|
||||
.AddBaseDbContextPool<WebhooksDbContext>();
|
||||
|
||||
if (AddAndUseSession)
|
||||
{
|
||||
@ -294,20 +295,35 @@ public abstract class BaseStartup
|
||||
|
||||
app.UseLoggerMiddleware();
|
||||
|
||||
app.UseEndpoints(async endpoints =>
|
||||
app.UseEndpoints(async endpoints =>
|
||||
{
|
||||
await endpoints.MapCustom(WebhooksEnabled, app.ApplicationServices);
|
||||
await endpoints.MapCustomAsync(WebhooksEnabled, app.ApplicationServices);
|
||||
|
||||
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
Predicate = _ => true,
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/ready", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name.Contains("services")
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name.Contains("self")
|
||||
});
|
||||
});
|
||||
|
||||
app.Map("/switch", appBuilder =>
|
||||
{
|
||||
appBuilder.Run(async context =>
|
||||
{
|
||||
CustomHealthCheck.Running = !CustomHealthCheck.Running;
|
||||
await context.Response.WriteAsync($"{Environment.MachineName} running {CustomHealthCheck.Running}");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void ConfigureContainer(ContainerBuilder builder)
|
||||
|
@ -83,7 +83,7 @@ public static class EndpointExtension
|
||||
"DELETE"
|
||||
};
|
||||
|
||||
public static async Task<IEndpointRouteBuilder> MapCustom(this IEndpointRouteBuilder endpoints, bool webhooksEnabled = false, IServiceProvider serviceProvider = null)
|
||||
public static async Task<IEndpointRouteBuilder> MapCustomAsync(this IEndpointRouteBuilder endpoints, bool webhooksEnabled = false, IServiceProvider serviceProvider = null)
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
|
||||
|
@ -23,67 +23,35 @@
|
||||
// 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.Api.Core.Core;
|
||||
|
||||
public static class CustomHealthCheck
|
||||
{
|
||||
{
|
||||
public static bool Running { get; set;}
|
||||
|
||||
static CustomHealthCheck()
|
||||
{
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var hcBuilder = services.AddHealthChecks();
|
||||
|
||||
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy());
|
||||
|
||||
var configurationExtension = new ConfigurationExtension(configuration);
|
||||
|
||||
var connectionString = configurationExtension.GetConnectionStrings("default");
|
||||
var hcBuilder = services.AddHealthChecks();
|
||||
|
||||
if (string.Equals(connectionString.ProviderName, "MySql.Data.MySqlClient"))
|
||||
{
|
||||
hcBuilder.AddMySql(connectionString.ConnectionString,
|
||||
name: "mysqldb",
|
||||
tags: new string[] { "mysqldb" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
|
||||
if (string.Equals(connectionString.ProviderName, "Npgsql"))
|
||||
{
|
||||
hcBuilder.AddNpgSql(connectionString.ConnectionString,
|
||||
name: "postgredb",
|
||||
tags: new string[] { "postgredb" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
|
||||
var kafkaSettings = configurationExtension.GetSetting<KafkaSettings>("kafka");
|
||||
if (kafkaSettings != null && !string.IsNullOrEmpty(kafkaSettings.BootstrapServers))
|
||||
{
|
||||
var clientConfig = new ClientConfig { BootstrapServers = kafkaSettings.BootstrapServers };
|
||||
|
||||
hcBuilder.AddKafka(new ProducerConfig(clientConfig),
|
||||
name: "kafka",
|
||||
tags: new string[] { "kafka" },
|
||||
timeout: new TimeSpan(0,0,15)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
var elasticSettings = configuration.GetSection("elastic");
|
||||
|
||||
if (elasticSettings != null && elasticSettings.GetChildren().Any())
|
||||
{
|
||||
var host = elasticSettings.GetSection("Host").Value ?? "localhost";
|
||||
var scheme = elasticSettings.GetSection("Scheme").Value ?? "http";
|
||||
var port = elasticSettings.GetSection("Port").Value ?? "9200";
|
||||
var elasticSearchUri = $"{scheme}://{host}:{port}";
|
||||
|
||||
if (Uri.IsWellFormedUriString(elasticSearchUri, UriKind.Absolute))
|
||||
{
|
||||
hcBuilder.AddElasticsearch(elasticSearchUri,
|
||||
name: "elasticsearch",
|
||||
tags: new string[] { "elasticsearch" });
|
||||
}
|
||||
}
|
||||
hcBuilder.AddCheck("self", () => Running ? HealthCheckResult.Healthy()
|
||||
: HealthCheckResult.Unhealthy())
|
||||
.AddDatabase(configuration)
|
||||
.AddDistibutedCache(configuration)
|
||||
.AddMessageQueue(configuration)
|
||||
.AddSearch(configuration);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IHealthChecksBuilder AddDistibutedCache(
|
||||
this IHealthChecksBuilder hcBuilder, IConfiguration configuration)
|
||||
{
|
||||
var redisConfiguration = configuration.GetSection("Redis").Get<RedisConfiguration>();
|
||||
|
||||
if (redisConfiguration != null)
|
||||
@ -97,20 +65,97 @@ public static class CustomHealthCheck
|
||||
|
||||
hcBuilder.AddRedis(redisConfiguration.ConfigurationOptions.ToString(),
|
||||
name: "redis",
|
||||
tags: new string[] { "redis" },
|
||||
tags: new string[] { "redis", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
|
||||
return hcBuilder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static IHealthChecksBuilder AddSearch(
|
||||
this IHealthChecksBuilder hcBuilder, IConfiguration configuration)
|
||||
{
|
||||
var elasticSettings = configuration.GetSection("elastic");
|
||||
|
||||
if (elasticSettings != null && elasticSettings.GetChildren().Any())
|
||||
{
|
||||
var host = elasticSettings.GetSection("Host").Value ?? "localhost";
|
||||
var scheme = elasticSettings.GetSection("Scheme").Value ?? "http";
|
||||
var port = elasticSettings.GetSection("Port").Value ?? "9200";
|
||||
var elasticSearchUri = $"{scheme}://{host}:{port}";
|
||||
|
||||
if (Uri.IsWellFormedUriString(elasticSearchUri, UriKind.Absolute))
|
||||
{
|
||||
hcBuilder.AddElasticsearch(elasticSearchUri,
|
||||
name: "elasticsearch",
|
||||
tags: new string[] { "elasticsearch", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
}
|
||||
|
||||
return hcBuilder;
|
||||
}
|
||||
|
||||
public static IHealthChecksBuilder AddDatabase(
|
||||
this IHealthChecksBuilder hcBuilder, IConfiguration configuration)
|
||||
{
|
||||
var configurationExtension = new ConfigurationExtension(configuration);
|
||||
|
||||
var connectionString = configurationExtension.GetConnectionStrings("default");
|
||||
|
||||
if (string.Equals(connectionString.ProviderName, "MySql.Data.MySqlClient"))
|
||||
{
|
||||
hcBuilder.AddMySql(connectionString.ConnectionString,
|
||||
name: "mysqldb",
|
||||
tags: new string[] { "mysqldb", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
else if (string.Equals(connectionString.ProviderName, "Npgsql"))
|
||||
{
|
||||
hcBuilder.AddNpgSql(connectionString.ConnectionString,
|
||||
name: "postgredb",
|
||||
tags: new string[] { "postgredb", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
|
||||
return hcBuilder;
|
||||
}
|
||||
|
||||
|
||||
public static IHealthChecksBuilder AddMessageQueue(
|
||||
this IHealthChecksBuilder hcBuilder, IConfiguration configuration)
|
||||
{
|
||||
var rabbitMQConfiguration = configuration.GetSection("RabbitMQ").Get<RabbitMQSettings>();
|
||||
|
||||
if (rabbitMQConfiguration != null)
|
||||
{
|
||||
hcBuilder.AddRabbitMQ(x => rabbitMQConfiguration.GetConnectionFactory(),
|
||||
name: "rabbitMQ",
|
||||
tags: new string[] { "rabbitMQ" },
|
||||
tags: new string[] { "rabbitMQ", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15));
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
else
|
||||
{
|
||||
var configurationExtension = new ConfigurationExtension(configuration);
|
||||
var kafkaSettings = configurationExtension.GetSetting<KafkaSettings>("kafka");
|
||||
|
||||
if (kafkaSettings != null && !string.IsNullOrEmpty(kafkaSettings.BootstrapServers))
|
||||
{
|
||||
var clientConfig = new ClientConfig { BootstrapServers = kafkaSettings.BootstrapServers };
|
||||
|
||||
hcBuilder.AddKafka(new ProducerConfig(clientConfig),
|
||||
name: "kafka",
|
||||
tags: new string[] { "kafka", "services" },
|
||||
timeout: new TimeSpan(0, 0, 15)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return hcBuilder;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -29,11 +29,11 @@ public static class QuotaExtension
|
||||
{
|
||||
public static IServiceCollection RegisterFeature(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<ITenantQuotaFeatureChecker, CountRoomAdminChecker>();
|
||||
services.AddScoped<TenantQuotaFeatureCheckerCount<CountRoomAdminFeature>, CountRoomAdminChecker>();
|
||||
services.AddScoped<CountRoomAdminChecker>();
|
||||
services.AddScoped<ITenantQuotaFeatureStat<CountRoomAdminFeature, int>, CountRoomAdminStatistic>();
|
||||
services.AddScoped<CountRoomAdminStatistic>();
|
||||
services.AddScoped<ITenantQuotaFeatureChecker, CountPaidUserChecker>();
|
||||
services.AddScoped<TenantQuotaFeatureCheckerCount<CountPaidUserFeature>, CountPaidUserChecker>();
|
||||
services.AddScoped<CountPaidUserChecker>();
|
||||
services.AddScoped<ITenantQuotaFeatureStat<CountPaidUserFeature, int>, CountPaidUserStatistic>();
|
||||
services.AddScoped<CountPaidUserStatistic>();
|
||||
|
||||
services.AddScoped<ITenantQuotaFeatureChecker, CountUserChecker>();
|
||||
services.AddScoped<TenantQuotaFeatureCheckerCount<CountUserFeature>, CountUserChecker>();
|
||||
|
@ -49,7 +49,7 @@ public static class ServiceCollectionExtension
|
||||
{
|
||||
services.AddSingleton(typeof(ICacheNotify<>), typeof(RabbitMQCache<>));
|
||||
}
|
||||
else if (kafkaConfiguration != null)
|
||||
else if (kafkaConfiguration != null && !string.IsNullOrEmpty(kafkaConfiguration.BootstrapServers))
|
||||
{
|
||||
services.AddSingleton(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
|
||||
}
|
||||
|
@ -1,139 +1,140 @@
|
||||
// (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.Web.Api.Models;
|
||||
|
||||
public class EmployeeFullDto : EmployeeDto
|
||||
{
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Email { get; set; }
|
||||
public List<Contact> Contacts { get; set; }
|
||||
public ApiDateTime Birthday { get; set; }
|
||||
public string Sex { get; set; }
|
||||
public EmployeeStatus Status { get; set; }
|
||||
public EmployeeActivationStatus ActivationStatus { get; set; }
|
||||
public ApiDateTime Terminated { get; set; }
|
||||
public string Department { get; set; }
|
||||
public ApiDateTime WorkFrom { get; set; }
|
||||
public List<GroupSummaryDto> Groups { get; set; }
|
||||
public string Location { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public string AvatarMax { get; set; }
|
||||
public string AvatarMedium { get; set; }
|
||||
public string Avatar { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public bool IsLDAP { get; set; }
|
||||
public List<string> ListAdminModules { get; set; }
|
||||
public bool IsOwner { get; set; }
|
||||
public bool IsVisitor { get; set; }
|
||||
public string CultureName { get; set; }
|
||||
public string MobilePhone { get; set; }
|
||||
public MobilePhoneActivationStatus MobilePhoneActivationStatus { get; set; }
|
||||
// (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.Web.Api.Models;
|
||||
|
||||
public class EmployeeFullDto : EmployeeDto
|
||||
{
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Email { get; set; }
|
||||
public List<Contact> Contacts { get; set; }
|
||||
public ApiDateTime Birthday { get; set; }
|
||||
public string Sex { get; set; }
|
||||
public EmployeeStatus Status { get; set; }
|
||||
public EmployeeActivationStatus ActivationStatus { get; set; }
|
||||
public ApiDateTime Terminated { get; set; }
|
||||
public string Department { get; set; }
|
||||
public ApiDateTime WorkFrom { get; set; }
|
||||
public List<GroupSummaryDto> Groups { get; set; }
|
||||
public string Location { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public string AvatarMax { get; set; }
|
||||
public string AvatarMedium { get; set; }
|
||||
public string Avatar { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public bool IsLDAP { get; set; }
|
||||
public List<string> ListAdminModules { get; set; }
|
||||
public bool IsOwner { get; set; }
|
||||
public bool IsVisitor { get; set; }
|
||||
public bool IsCollaborator { get; set; }
|
||||
public string CultureName { get; set; }
|
||||
public string MobilePhone { get; set; }
|
||||
public MobilePhoneActivationStatus MobilePhoneActivationStatus { get; set; }
|
||||
public bool IsSSO { get; set; }
|
||||
public DarkThemeSettingsEnum? Theme { get; set; }
|
||||
public long QuotaLimit { get; set; }
|
||||
public double UsedSpace { get; set; }
|
||||
|
||||
public static new EmployeeFullDto GetSample()
|
||||
{
|
||||
return new EmployeeFullDto
|
||||
{
|
||||
Avatar = "url to big avatar",
|
||||
AvatarSmall = "url to small avatar",
|
||||
AvatarMax = "url to max avatar",
|
||||
Contacts = new List<Contact> { Contact.GetSample() },
|
||||
Email = "my@gmail.com",
|
||||
FirstName = "Mike",
|
||||
Id = Guid.Empty,
|
||||
IsAdmin = false,
|
||||
ListAdminModules = new List<string> { "projects", "crm" },
|
||||
UserName = "Mike.Zanyatski",
|
||||
LastName = "Zanyatski",
|
||||
Title = "Manager",
|
||||
Groups = new List<GroupSummaryDto> { GroupSummaryDto.GetSample() },
|
||||
AvatarMedium = "url to medium avatar",
|
||||
Birthday = ApiDateTime.GetSample(),
|
||||
Department = "Marketing",
|
||||
Location = "Palo Alto",
|
||||
Notes = "Notes to worker",
|
||||
Sex = "male",
|
||||
Status = EmployeeStatus.Active,
|
||||
WorkFrom = ApiDateTime.GetSample(),
|
||||
Terminated = ApiDateTime.GetSample(),
|
||||
CultureName = "en-EN",
|
||||
IsLDAP = false,
|
||||
IsSSO = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
{
|
||||
private readonly ApiContext _context;
|
||||
private readonly WebItemSecurity _webItemSecurity;
|
||||
|
||||
public static new EmployeeFullDto GetSample()
|
||||
{
|
||||
return new EmployeeFullDto
|
||||
{
|
||||
Avatar = "url to big avatar",
|
||||
AvatarSmall = "url to small avatar",
|
||||
AvatarMax = "url to max avatar",
|
||||
Contacts = new List<Contact> { Contact.GetSample() },
|
||||
Email = "my@gmail.com",
|
||||
FirstName = "Mike",
|
||||
Id = Guid.Empty,
|
||||
IsAdmin = false,
|
||||
ListAdminModules = new List<string> { "projects", "crm" },
|
||||
UserName = "Mike.Zanyatski",
|
||||
LastName = "Zanyatski",
|
||||
Title = "Manager",
|
||||
Groups = new List<GroupSummaryDto> { GroupSummaryDto.GetSample() },
|
||||
AvatarMedium = "url to medium avatar",
|
||||
Birthday = ApiDateTime.GetSample(),
|
||||
Department = "Marketing",
|
||||
Location = "Palo Alto",
|
||||
Notes = "Notes to worker",
|
||||
Sex = "male",
|
||||
Status = EmployeeStatus.Active,
|
||||
WorkFrom = ApiDateTime.GetSample(),
|
||||
Terminated = ApiDateTime.GetSample(),
|
||||
CultureName = "en-EN",
|
||||
IsLDAP = false,
|
||||
IsSSO = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
{
|
||||
private readonly ApiContext _context;
|
||||
private readonly WebItemSecurity _webItemSecurity;
|
||||
private readonly ApiDateTimeHelper _apiDateTimeHelper;
|
||||
private readonly WebItemManager _webItemManager;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly IQuotaService _quotaService;
|
||||
|
||||
public EmployeeFullDtoHelper(
|
||||
ApiContext context,
|
||||
UserManager userManager,
|
||||
UserPhotoManager userPhotoManager,
|
||||
WebItemSecurity webItemSecurity,
|
||||
CommonLinkUtility commonLinkUtility,
|
||||
DisplayUserSettingsHelper displayUserSettingsHelper,
|
||||
public EmployeeFullDtoHelper(
|
||||
ApiContext context,
|
||||
UserManager userManager,
|
||||
UserPhotoManager userPhotoManager,
|
||||
WebItemSecurity webItemSecurity,
|
||||
CommonLinkUtility commonLinkUtility,
|
||||
DisplayUserSettingsHelper displayUserSettingsHelper,
|
||||
ApiDateTimeHelper apiDateTimeHelper,
|
||||
WebItemManager webItemManager,
|
||||
SettingsManager settingsManager,
|
||||
IQuotaService quotaService)
|
||||
: base(context, displayUserSettingsHelper, userPhotoManager, commonLinkUtility, userManager)
|
||||
{
|
||||
_context = context;
|
||||
_webItemSecurity = webItemSecurity;
|
||||
IQuotaService quotaService)
|
||||
: base(context, displayUserSettingsHelper, userPhotoManager, commonLinkUtility, userManager)
|
||||
{
|
||||
_context = context;
|
||||
_webItemSecurity = webItemSecurity;
|
||||
_apiDateTimeHelper = apiDateTimeHelper;
|
||||
_webItemManager = webItemManager;
|
||||
_settingsManager = settingsManager;
|
||||
_quotaService = quotaService;
|
||||
}
|
||||
|
||||
public static Expression<Func<User, UserInfo>> GetExpression(ApiContext apiContext)
|
||||
{
|
||||
if (apiContext?.Fields == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var newExpr = Expression.New(typeof(UserInfo));
|
||||
|
||||
//i => new UserInfo { ID = i.id }
|
||||
var parameter = Expression.Parameter(typeof(User), "i");
|
||||
}
|
||||
|
||||
public static Expression<Func<User, UserInfo>> GetExpression(ApiContext apiContext)
|
||||
{
|
||||
if (apiContext?.Fields == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var newExpr = Expression.New(typeof(UserInfo));
|
||||
|
||||
//i => new UserInfo { ID = i.id }
|
||||
var parameter = Expression.Parameter(typeof(User), "i");
|
||||
var bindExprs = new List<MemberAssignment>();
|
||||
|
||||
//foreach (var field in apiContext.Fields)
|
||||
@ -151,12 +152,12 @@ public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
bindExprs.Add(Expression.Bind(typeof(UserInfo).GetProperty("Id"),
|
||||
Expression.Property(parameter, typeof(User).GetProperty("Id"))));
|
||||
}
|
||||
|
||||
var body = Expression.MemberInit(newExpr, bindExprs);
|
||||
var lambda = Expression.Lambda<Func<User, UserInfo>>(body, parameter);
|
||||
|
||||
return lambda;
|
||||
}
|
||||
|
||||
var body = Expression.MemberInit(newExpr, bindExprs);
|
||||
var lambda = Expression.Lambda<Func<User, UserInfo>>(body, parameter);
|
||||
|
||||
return lambda;
|
||||
}
|
||||
public async Task<EmployeeFullDto> GetSimple(UserInfo userInfo)
|
||||
{
|
||||
var result = new EmployeeFullDto
|
||||
@ -176,97 +177,97 @@ public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<EmployeeFullDto> GetFull(UserInfo userInfo)
|
||||
{
|
||||
var result = new EmployeeFullDto
|
||||
{
|
||||
UserName = userInfo.UserName,
|
||||
FirstName = userInfo.FirstName,
|
||||
LastName = userInfo.LastName,
|
||||
Birthday = _apiDateTimeHelper.Get(userInfo.BirthDate),
|
||||
Status = userInfo.Status,
|
||||
ActivationStatus = userInfo.ActivationStatus & ~EmployeeActivationStatus.AutoGenerated,
|
||||
Terminated = _apiDateTimeHelper.Get(userInfo.TerminatedDate),
|
||||
WorkFrom = _apiDateTimeHelper.Get(userInfo.WorkFromDate),
|
||||
Email = userInfo.Email,
|
||||
IsVisitor = _userManager.IsUser(userInfo),
|
||||
IsAdmin = _userManager.IsDocSpaceAdmin(userInfo),
|
||||
IsOwner = userInfo.IsOwner(_context.Tenant),
|
||||
IsLDAP = userInfo.IsLDAP(),
|
||||
|
||||
public async Task<EmployeeFullDto> GetFull(UserInfo userInfo)
|
||||
{
|
||||
var result = new EmployeeFullDto
|
||||
{
|
||||
UserName = userInfo.UserName,
|
||||
FirstName = userInfo.FirstName,
|
||||
LastName = userInfo.LastName,
|
||||
Birthday = _apiDateTimeHelper.Get(userInfo.BirthDate),
|
||||
Status = userInfo.Status,
|
||||
ActivationStatus = userInfo.ActivationStatus & ~EmployeeActivationStatus.AutoGenerated,
|
||||
Terminated = _apiDateTimeHelper.Get(userInfo.TerminatedDate),
|
||||
WorkFrom = _apiDateTimeHelper.Get(userInfo.WorkFromDate),
|
||||
Email = userInfo.Email,
|
||||
IsVisitor = _userManager.IsUser(userInfo),
|
||||
IsAdmin = _userManager.IsDocSpaceAdmin(userInfo),
|
||||
IsOwner = userInfo.IsOwner(_context.Tenant),
|
||||
IsCollaborator = _userManager.IsCollaborator(userInfo),
|
||||
IsLDAP = userInfo.IsLDAP(),
|
||||
IsSSO = userInfo.IsSSO()
|
||||
|
||||
};
|
||||
|
||||
|
||||
await Init(result, userInfo);
|
||||
|
||||
var quotaSettings = _settingsManager.Load<TenantUserQuotaSettings>();
|
||||
|
||||
|
||||
if (quotaSettings.EnableUserQuota)
|
||||
{
|
||||
result.UsedSpace = Math.Max(0, _quotaService.FindUserQuotaRows(_context.Tenant.Id, userInfo.Id).Where(r => !string.IsNullOrEmpty(r.Tag)).Sum(r => r.Counter));
|
||||
var userQuotaSettings = _settingsManager.LoadForUser<UserQuotaSettings>(userInfo);
|
||||
var userQuotaSettings = _settingsManager.Load<UserQuotaSettings>(userInfo);
|
||||
result.QuotaLimit = userQuotaSettings != null ? userQuotaSettings.UserQuota : quotaSettings.DefaultUserQuota;
|
||||
}
|
||||
|
||||
if (userInfo.Sex.HasValue)
|
||||
{
|
||||
result.Sex = userInfo.Sex.Value ? "male" : "female";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.Location))
|
||||
{
|
||||
result.Location = userInfo.Location;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.Notes))
|
||||
{
|
||||
result.Notes = userInfo.Notes;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.MobilePhone))
|
||||
{
|
||||
result.MobilePhone = userInfo.MobilePhone;
|
||||
}
|
||||
|
||||
result.MobilePhoneActivationStatus = userInfo.MobilePhoneActivationStatus;
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.CultureName))
|
||||
{
|
||||
result.CultureName = userInfo.CultureName;
|
||||
}
|
||||
|
||||
|
||||
if (userInfo.Sex.HasValue)
|
||||
{
|
||||
result.Sex = userInfo.Sex.Value ? "male" : "female";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.Location))
|
||||
{
|
||||
result.Location = userInfo.Location;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.Notes))
|
||||
{
|
||||
result.Notes = userInfo.Notes;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.MobilePhone))
|
||||
{
|
||||
result.MobilePhone = userInfo.MobilePhone;
|
||||
}
|
||||
|
||||
result.MobilePhoneActivationStatus = userInfo.MobilePhoneActivationStatus;
|
||||
|
||||
if (!string.IsNullOrEmpty(userInfo.CultureName))
|
||||
{
|
||||
result.CultureName = userInfo.CultureName;
|
||||
}
|
||||
|
||||
FillConacts(result, userInfo);
|
||||
FillGroups(result, userInfo);
|
||||
|
||||
var cacheKey = Math.Abs(userInfo.LastModified.GetHashCode());
|
||||
|
||||
|
||||
if (_context.Check("avatarMax"))
|
||||
{
|
||||
result.AvatarMax = await _userPhotoManager.GetMaxPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatarMedium"))
|
||||
{
|
||||
result.AvatarMedium = await _userPhotoManager.GetMediumPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatar"))
|
||||
{
|
||||
result.Avatar = await _userPhotoManager.GetBigPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("listAdminModules"))
|
||||
{
|
||||
|
||||
if (_context.Check("avatarMax"))
|
||||
{
|
||||
result.AvatarMax = await _userPhotoManager.GetMaxPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatarMedium"))
|
||||
{
|
||||
result.AvatarMedium = await _userPhotoManager.GetMediumPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatar"))
|
||||
{
|
||||
result.Avatar = await _userPhotoManager.GetBigPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("listAdminModules"))
|
||||
{
|
||||
var listAdminModules = userInfo.GetListAdminModules(_webItemSecurity, _webItemManager);
|
||||
if (listAdminModules.Count > 0)
|
||||
{
|
||||
result.ListAdminModules = listAdminModules;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
if (listAdminModules.Count > 0)
|
||||
{
|
||||
result.ListAdminModules = listAdminModules;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private void FillGroups(EmployeeFullDto result, UserInfo userInfo)
|
||||
{
|
||||
@ -289,27 +290,27 @@ public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
result.Department = "";
|
||||
}
|
||||
}
|
||||
|
||||
private void FillConacts(EmployeeFullDto employeeWraperFull, UserInfo userInfo)
|
||||
{
|
||||
if (userInfo.ContactsList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var contacts = new List<Contact>();
|
||||
|
||||
for (var i = 0; i < userInfo.ContactsList.Count; i += 2)
|
||||
{
|
||||
if (i + 1 < userInfo.ContactsList.Count)
|
||||
{
|
||||
contacts.Add(new Contact(userInfo.ContactsList[i], userInfo.ContactsList[i + 1]));
|
||||
}
|
||||
|
||||
private void FillConacts(EmployeeFullDto employeeWraperFull, UserInfo userInfo)
|
||||
{
|
||||
if (userInfo.ContactsList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (contacts.Count > 0)
|
||||
{
|
||||
employeeWraperFull.Contacts = contacts;
|
||||
}
|
||||
}
|
||||
var contacts = new List<Contact>();
|
||||
|
||||
for (var i = 0; i < userInfo.ContactsList.Count; i += 2)
|
||||
{
|
||||
if (i + 1 < userInfo.ContactsList.Count)
|
||||
{
|
||||
contacts.Add(new Contact(userInfo.ContactsList[i], userInfo.ContactsList[i + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (contacts.Count > 0)
|
||||
{
|
||||
employeeWraperFull.Contacts = contacts;
|
||||
}
|
||||
}
|
||||
}
|
@ -106,3 +106,4 @@ global using RabbitMQ.Client.Events;
|
||||
global using StackExchange.Redis.Extensions.Core.Abstractions;
|
||||
|
||||
global using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
global using System.Threading.Channels;
|
||||
|
@ -28,19 +28,12 @@ namespace ASC.Common.Security.Authorizing;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly Role DocSpaceAdmin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
|
||||
|
||||
public static readonly Role DocSpaceAdmin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "DocSpaceAdmin");
|
||||
public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone");
|
||||
|
||||
|
||||
public static readonly Role RoomAdmin = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "User");
|
||||
|
||||
public static readonly Role User = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "Visitor");
|
||||
|
||||
|
||||
public static readonly Role RoomAdmin = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "RoomAdmin");
|
||||
public static readonly Role Collaborator = new Role(new Guid("88f11e7c-7407-4bea-b4cb-070010cdbb6b"), "Collaborator");
|
||||
public static readonly Role User = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "User");
|
||||
public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member");
|
||||
|
||||
public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner");
|
||||
|
||||
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
|
||||
}
|
||||
|
114
common/ASC.Common/Threading/Channel/ChannelExtension.cs
Normal file
114
common/ASC.Common/Threading/Channel/ChannelExtension.cs
Normal file
@ -0,0 +1,114 @@
|
||||
// (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.Common.Threading;
|
||||
public static class ChannelExtension
|
||||
{
|
||||
public static IList<ChannelReader<T>> Split<T>(this ChannelReader<T> ch, int n, Func<int, int, T, int> selector = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var outputs = new Channel<T>[n];
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
outputs[i] = Channel.CreateUnbounded<T>();
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var index = 0;
|
||||
|
||||
await foreach (var item in ch.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
if (selector == null)
|
||||
{
|
||||
index = (index + 1) % n;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = selector(n, index, item);
|
||||
}
|
||||
|
||||
await outputs[index].Writer.WriteAsync(item, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// TODO: catch error via additional channel
|
||||
// var error = Channel.CreateUnbounded<T>();
|
||||
// await error.Writer.WriteAsync(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var ch in outputs)
|
||||
{
|
||||
ch.Writer.Complete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return outputs.Select(ch => ch.Reader).ToArray();
|
||||
}
|
||||
|
||||
public static ChannelReader<T> Merge<T>(this IEnumerable<ChannelReader<T>> inputs, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var output = Channel.CreateUnbounded<T>();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
async Task Redirect(ChannelReader<T> input)
|
||||
{
|
||||
await foreach (var item in input.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
await output.Writer.WriteAsync(item, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(inputs.Select(i => Redirect(i)).ToArray());
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// TODO: catch error via additional channel
|
||||
// var error = Channel.CreateUnbounded<T>();
|
||||
// await error.Writer.WriteAsync(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
output.Writer.Complete();
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
@ -39,16 +39,17 @@ public class SubscriptionManager
|
||||
{
|
||||
Constants.DocSpaceAdmin.ID,
|
||||
Constants.Everyone.ID,
|
||||
Constants.RoomAdmin.ID
|
||||
Constants.RoomAdmin.ID,
|
||||
Constants.Collaborator.ID,
|
||||
};
|
||||
|
||||
|
||||
public SubscriptionManager(CachedSubscriptionService service, TenantManager tenantManager, ICache cache)
|
||||
{
|
||||
_service = service ?? throw new ArgumentNullException("subscriptionManager");
|
||||
_tenantManager = tenantManager;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Subscribe(string sourceID, string actionID, string objectID, string recipientID)
|
||||
{
|
||||
var s = new SubscriptionRecord
|
||||
@ -79,7 +80,7 @@ public class SubscriptionManager
|
||||
|
||||
_service.SaveSubscription(s);
|
||||
}
|
||||
|
||||
|
||||
public void Unsubscribe(string sourceID, string actionID, string objectID, string recipientID)
|
||||
{
|
||||
var s = new SubscriptionRecord
|
||||
@ -110,17 +111,17 @@ public class SubscriptionManager
|
||||
|
||||
_service.SaveSubscription(s);
|
||||
}
|
||||
|
||||
|
||||
public void UnsubscribeAll(string sourceID, string actionID, string objectID)
|
||||
{
|
||||
_service.RemoveSubscriptions(GetTenant(), sourceID, actionID, objectID);
|
||||
}
|
||||
|
||||
|
||||
public void UnsubscribeAll(string sourceID, string actionID)
|
||||
{
|
||||
_service.RemoveSubscriptions(GetTenant(), sourceID, actionID);
|
||||
}
|
||||
|
||||
|
||||
public string[] GetSubscriptionMethod(string sourceID, string actionID, string recipientID)
|
||||
{
|
||||
IEnumerable<SubscriptionMethod> methods;
|
||||
@ -144,27 +145,27 @@ public class SubscriptionManager
|
||||
|
||||
return m != null ? m.Methods : Array.Empty<string>();
|
||||
}
|
||||
|
||||
|
||||
public string[] GetRecipients(string sourceID, string actionID, string objectID)
|
||||
{
|
||||
return _service.GetRecipients(GetTenant(), sourceID, actionID, objectID);
|
||||
}
|
||||
|
||||
|
||||
public object GetSubscriptionRecord(string sourceID, string actionID, string recipientID, string objectID)
|
||||
{
|
||||
return _service.GetSubscription(GetTenant(), sourceID, actionID, recipientID, objectID);
|
||||
}
|
||||
|
||||
|
||||
public string[] GetSubscriptions(string sourceID, string actionID, string recipientID, bool checkSubscribe = true)
|
||||
{
|
||||
return _service.GetSubscriptions(GetTenant(), sourceID, actionID, recipientID, checkSubscribe);
|
||||
}
|
||||
|
||||
|
||||
public bool IsUnsubscribe(string sourceID, string recipientID, string actionID, string objectID)
|
||||
{
|
||||
return _service.IsUnsubscribe(GetTenant(), sourceID, actionID, recipientID, objectID);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateSubscriptionMethod(string sourceID, string actionID, string recipientID, string[] senderNames)
|
||||
{
|
||||
var m = new SubscriptionMethod
|
||||
@ -215,5 +216,5 @@ public class SubscriptionManager
|
||||
private int GetTenant()
|
||||
{
|
||||
return _tenantManager.GetCurrentTenant().Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ public class TenantManager
|
||||
internal CoreBaseSettings CoreBaseSettings { get; set; }
|
||||
internal CoreSettings CoreSettings { get; set; }
|
||||
|
||||
private readonly static object _lock = new object();
|
||||
|
||||
static TenantManager()
|
||||
{
|
||||
_thisCompAddresses.Add("localhost");
|
||||
@ -333,7 +335,10 @@ public class TenantManager
|
||||
|
||||
public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange)
|
||||
{
|
||||
QuotaService.SetTenantQuotaRow(row, exchange);
|
||||
lock (_lock)
|
||||
{
|
||||
QuotaService.SetTenantQuotaRow(row, exchange);
|
||||
}
|
||||
}
|
||||
|
||||
public List<TenantQuotaRow> FindTenantQuotaRows(int tenantId)
|
||||
|
@ -61,7 +61,7 @@ public class UserManager
|
||||
private readonly CardDavAddressbook _cardDavAddressbook;
|
||||
private readonly ILogger<UserManager> _log;
|
||||
private readonly ICache _cache;
|
||||
private readonly TenantQuotaFeatureCheckerCount<CountRoomAdminFeature> _countRoomAdminChecker;
|
||||
private readonly TenantQuotaFeatureCheckerCount<CountPaidUserFeature> _countPaidUserChecker;
|
||||
private readonly TenantQuotaFeatureCheckerCount<CountUserFeature> _activeUsersFeatureChecker;
|
||||
private readonly Constants _constants;
|
||||
private readonly UserFormatter _userFormatter;
|
||||
@ -86,7 +86,7 @@ public class UserManager
|
||||
CardDavAddressbook cardDavAddressbook,
|
||||
ILogger<UserManager> log,
|
||||
ICache cache,
|
||||
TenantQuotaFeatureCheckerCount<CountRoomAdminFeature> countRoomAdrminChecker,
|
||||
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> countPaidUserChecker,
|
||||
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
||||
UserFormatter userFormatter
|
||||
)
|
||||
@ -102,7 +102,7 @@ public class UserManager
|
||||
_cardDavAddressbook = cardDavAddressbook;
|
||||
_log = log;
|
||||
_cache = cache;
|
||||
_countRoomAdminChecker = countRoomAdrminChecker;
|
||||
_countPaidUserChecker = countPaidUserChecker;
|
||||
_activeUsersFeatureChecker = activeUsersFeatureChecker;
|
||||
_constants = _userManagerConstants.Constants;
|
||||
_userFormatter = userFormatter;
|
||||
@ -120,7 +120,7 @@ public class UserManager
|
||||
CardDavAddressbook cardDavAddressbook,
|
||||
ILogger<UserManager> log,
|
||||
ICache cache,
|
||||
TenantQuotaFeatureCheckerCount<CountRoomAdminFeature> tenantQuotaFeatureChecker,
|
||||
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> tenantQuotaFeatureChecker,
|
||||
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
UserFormatter userFormatter)
|
||||
@ -157,10 +157,16 @@ public class UserManager
|
||||
switch (type)
|
||||
{
|
||||
case EmployeeType.RoomAdmin:
|
||||
users = users.Where(u => !this.IsUser(u));
|
||||
users = users.Where(u => !this.IsUser(u) && !this.IsCollaborator(u) && !this.IsDocSpaceAdmin(u));
|
||||
break;
|
||||
case EmployeeType.DocSpaceAdmin:
|
||||
users = users.Where(this.IsDocSpaceAdmin);
|
||||
break;
|
||||
case EmployeeType.Collaborator:
|
||||
users = users.Where(this.IsCollaborator);
|
||||
break;
|
||||
case EmployeeType.User:
|
||||
users = users.Where(u => this.IsUser(u));
|
||||
users = users.Where(this.IsUser);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -354,15 +360,14 @@ public class UserManager
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public async Task<UserInfo> SaveUserInfo(UserInfo u, bool isVisitor = false, bool syncCardDav = false)
|
||||
public async Task<UserInfo> SaveUserInfo(UserInfo u, EmployeeType type = EmployeeType.RoomAdmin, bool syncCardDav = false, bool paidUserQuotaCheck = true)
|
||||
{
|
||||
if (IsSystemUser(u.Id))
|
||||
{
|
||||
return SystemUsers[u.Id];
|
||||
}
|
||||
|
||||
_permissionContext.DemandPermissions(new UserSecurityProvider(u.Id, isVisitor ? EmployeeType.User : EmployeeType.RoomAdmin),
|
||||
Constants.Action_AddRemoveUser);
|
||||
_permissionContext.DemandPermissions(new UserSecurityProvider(u.Id, type), Constants.Action_AddRemoveUser);
|
||||
|
||||
if (!_coreBaseSettings.Personal)
|
||||
{
|
||||
@ -379,13 +384,13 @@ public class UserManager
|
||||
throw new InvalidOperationException("User already exist.");
|
||||
}
|
||||
|
||||
if (isVisitor)
|
||||
if (type is EmployeeType.User)
|
||||
{
|
||||
await _activeUsersFeatureChecker.CheckAppend();
|
||||
}
|
||||
else
|
||||
else if (paidUserQuotaCheck)
|
||||
{
|
||||
await _countRoomAdminChecker.CheckAppend();
|
||||
await _countPaidUserChecker.CheckAppend();
|
||||
}
|
||||
|
||||
var newUser = _userService.SaveUser(_tenantManager.GetCurrentTenant().Id, u);
|
||||
@ -886,16 +891,23 @@ public class UserManager
|
||||
}
|
||||
|
||||
UserGroupRef r;
|
||||
if (groupId == Constants.GroupManager.ID || groupId == Constants.GroupUser.ID)
|
||||
if (groupId == Constants.GroupManager.ID || groupId == Constants.GroupUser.ID || groupId == Constants.GroupCollaborator.ID)
|
||||
{
|
||||
var user = refs.TryGetValue(UserGroupRef.CreateKey(Tenant.Id, userId, Constants.GroupUser.ID, UserGroupRefType.Contains), out r) && !r.Removed;
|
||||
var isUser = refs.TryGetValue(UserGroupRef.CreateKey(Tenant.Id, userId, Constants.GroupUser.ID, UserGroupRefType.Contains), out r) && !r.Removed;
|
||||
if (groupId == Constants.GroupUser.ID)
|
||||
{
|
||||
return user;
|
||||
return isUser;
|
||||
}
|
||||
|
||||
var isCollaborator = refs.TryGetValue(UserGroupRef.CreateKey(Tenant.Id, userId, Constants.GroupCollaborator.ID, UserGroupRefType.Contains), out r) && !r.Removed;
|
||||
if (groupId == Constants.GroupCollaborator.ID)
|
||||
{
|
||||
return isCollaborator;
|
||||
}
|
||||
|
||||
if (groupId == Constants.GroupManager.ID)
|
||||
{
|
||||
return !user;
|
||||
return !isUser && !isCollaborator;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,4 +38,5 @@ public enum EmployeeType
|
||||
RoomAdmin = 1,
|
||||
User = 2,
|
||||
DocSpaceAdmin = 3,
|
||||
}
|
||||
Collaborator = 4,
|
||||
}
|
@ -88,16 +88,9 @@ public class DbLoginEventsManager
|
||||
{
|
||||
using var loginEventContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var events = await loginEventContext.LoginEvents
|
||||
await loginEventContext.LoginEvents
|
||||
.Where(r => r.Id == loginEventId)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await loginEventContext.SaveChangesAsync();
|
||||
.ExecuteUpdateAsync(r => r.SetProperty(p => p.Active, false));
|
||||
|
||||
ResetCache();
|
||||
}
|
||||
@ -106,16 +99,9 @@ public class DbLoginEventsManager
|
||||
{
|
||||
using var loginEventContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var events = await loginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await loginEventContext.SaveChangesAsync();
|
||||
await loginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && r.Active)
|
||||
.ExecuteUpdateAsync(r => r.SetProperty(p => p.Active, false));
|
||||
|
||||
ResetCache(tenantId, userId);
|
||||
}
|
||||
@ -124,32 +110,18 @@ public class DbLoginEventsManager
|
||||
{
|
||||
using var loginEventContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var events = await loginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await loginEventContext.SaveChangesAsync();
|
||||
await loginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.Active)
|
||||
.ExecuteUpdateAsync(r => r.SetProperty(p => p.Active, false));
|
||||
}
|
||||
|
||||
public async Task LogOutAllActiveConnectionsExceptThis(int loginEventId, int tenantId, Guid userId)
|
||||
{
|
||||
using var loginEventContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var events = await loginEventContext.LoginEvents
|
||||
await loginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && r.Id != loginEventId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await loginEventContext.SaveChangesAsync();
|
||||
.ExecuteUpdateAsync(r => r.SetProperty(p => p.Active, false));
|
||||
|
||||
ResetCache(tenantId, userId);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
namespace ASC.Core.Common.Settings;
|
||||
|
||||
[Singletone]
|
||||
public class DbSettingsManagerCache
|
||||
@ -46,11 +46,11 @@ public class DbSettingsManagerCache
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class DbSettingsManager
|
||||
public class SettingsManager
|
||||
{
|
||||
private readonly TimeSpan _expirationTimeout = TimeSpan.FromMinutes(5);
|
||||
|
||||
private readonly ILogger<DbSettingsManager> _logger;
|
||||
private readonly ILogger<SettingsManager> _logger;
|
||||
private readonly ICache _cache;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly DbSettingsManagerCache _dbSettingsManagerCache;
|
||||
@ -58,10 +58,10 @@ public class DbSettingsManager
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly IDbContextFactory<WebstudioDbContext> _dbContextFactory;
|
||||
|
||||
public DbSettingsManager(
|
||||
public SettingsManager(
|
||||
IServiceProvider serviceProvider,
|
||||
DbSettingsManagerCache dbSettingsManagerCache,
|
||||
ILogger<DbSettingsManager> logger,
|
||||
ILogger<SettingsManager> logger,
|
||||
AuthContext authContext,
|
||||
TenantManager tenantManager,
|
||||
IDbContextFactory<WebstudioDbContext> dbContextFactory)
|
||||
@ -100,96 +100,100 @@ public class DbSettingsManager
|
||||
}
|
||||
}
|
||||
|
||||
public bool SaveSettings<T>(T settings, int tenantId) where T : class, ISettings<T>
|
||||
public void ClearCache<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return SaveSettingsFor(settings, tenantId, Guid.Empty);
|
||||
}
|
||||
|
||||
public T LoadSettings<T>(int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
return LoadSettingsFor<T>(tenantId, Guid.Empty);
|
||||
ClearCache<T>(TenantID);
|
||||
}
|
||||
|
||||
public void ClearCache<T>(int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
var settings = LoadSettings<T>(tenantId);
|
||||
var settings = Load<T>(tenantId, Guid.Empty);
|
||||
var key = settings.ID.ToString() + tenantId + Guid.Empty;
|
||||
|
||||
_dbSettingsManagerCache.Remove(key);
|
||||
}
|
||||
|
||||
|
||||
public bool SaveSettingsFor<T>(T settings, int tenantId, Guid userId) where T : class, ISettings<T>
|
||||
public T GetDefault<T>() where T : class, ISettings<T>
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(settings);
|
||||
|
||||
using var webstudioDbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
try
|
||||
{
|
||||
var key = settings.ID.ToString() + tenantId + userId;
|
||||
var data = Serialize(settings);
|
||||
var def = GetDefault<T>();
|
||||
|
||||
var defaultData = Serialize(def);
|
||||
|
||||
if (data.SequenceEqual(defaultData))
|
||||
{
|
||||
var strategy = webstudioDbContext.Database.CreateExecutionStrategy();
|
||||
|
||||
strategy.Execute(() =>
|
||||
{
|
||||
using var tr = webstudioDbContext.Database.BeginTransaction();
|
||||
// remove default settings
|
||||
var s = webstudioDbContext.WebstudioSettings
|
||||
.Where(r => r.Id == settings.ID)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.Where(r => r.UserId == userId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
webstudioDbContext.WebstudioSettings.Remove(s);
|
||||
}
|
||||
|
||||
webstudioDbContext.SaveChanges();
|
||||
|
||||
tr.Commit();
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = new DbWebstudioSettings
|
||||
{
|
||||
Id = settings.ID,
|
||||
UserId = userId,
|
||||
TenantId = tenantId,
|
||||
Data = data
|
||||
};
|
||||
|
||||
webstudioDbContext.AddOrUpdate(webstudioDbContext.WebstudioSettings, s);
|
||||
|
||||
webstudioDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
_dbSettingsManagerCache.Remove(key);
|
||||
|
||||
_cache.Insert(key, settings, _expirationTimeout);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorSaveSettingsFor(ex);
|
||||
|
||||
return false;
|
||||
}
|
||||
var settingsInstance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
|
||||
return settingsInstance.GetDefault();
|
||||
}
|
||||
|
||||
internal T LoadSettingsFor<T>(int tenantId, Guid userId) where T : class, ISettings<T>
|
||||
public T Load<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(TenantID, Guid.Empty);
|
||||
}
|
||||
|
||||
public T Load<T>(Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(TenantID, userId);
|
||||
}
|
||||
|
||||
public T Load<T>(UserInfo user) where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(TenantID, user.Id);
|
||||
}
|
||||
|
||||
public T Load<T>(int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(tenantId, Guid.Empty);
|
||||
}
|
||||
|
||||
public T LoadForDefaultTenant<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(Tenant.DefaultTenant);
|
||||
}
|
||||
|
||||
public T LoadForCurrentUser<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return Load<T>(CurrentUserID);
|
||||
}
|
||||
|
||||
public bool Save<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, TenantID, Guid.Empty);
|
||||
}
|
||||
|
||||
public bool Save<T>(T data, Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, TenantID, userId);
|
||||
}
|
||||
|
||||
public bool Save<T>(T data, UserInfo user) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, TenantID, user.Id);
|
||||
}
|
||||
|
||||
public bool Save<T>(T data, int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, tenantId, Guid.Empty);
|
||||
}
|
||||
|
||||
public bool SaveForDefaultTenant<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, Tenant.DefaultTenant);
|
||||
}
|
||||
|
||||
public bool SaveForCurrentUser<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return Save(data, CurrentUserID);
|
||||
}
|
||||
|
||||
public bool Manage<T>(Action<T> action) where T : class, ISettings<T>
|
||||
{
|
||||
var settings = Load<T>();
|
||||
action(settings);
|
||||
return Save(settings);
|
||||
}
|
||||
|
||||
public bool ManageForCurrentUser<T>(Action<T> action) where T : class, ISettings<T>
|
||||
{
|
||||
var settings = LoadForCurrentUser<T>();
|
||||
action(settings);
|
||||
return SaveForCurrentUser(settings);
|
||||
}
|
||||
|
||||
internal T Load<T>(int tenantId, Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
var def = GetDefault<T>();
|
||||
var key = def.ID.ToString() + tenantId + userId;
|
||||
@ -231,75 +235,71 @@ public class DbSettingsManager
|
||||
return def;
|
||||
}
|
||||
|
||||
public T GetDefault<T>() where T : class, ISettings<T>
|
||||
private bool Save<T>(T settings, int tenantId, Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
var settingsInstance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
|
||||
return settingsInstance.GetDefault();
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(settings);
|
||||
|
||||
public T Load<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return LoadSettings<T>(TenantID);
|
||||
}
|
||||
using var webstudioDbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
public T LoadForCurrentUser<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return LoadForUser<T>(CurrentUserID);
|
||||
}
|
||||
try
|
||||
{
|
||||
var key = settings.ID.ToString() + tenantId + userId;
|
||||
var data = Serialize(settings);
|
||||
var def = GetDefault<T>();
|
||||
|
||||
public T LoadForUser<T>(Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
return LoadSettingsFor<T>(TenantID, userId);
|
||||
}
|
||||
var defaultData = Serialize(def);
|
||||
|
||||
public T LoadForUser<T>(UserInfo user) where T : class, ISettings<T>
|
||||
{
|
||||
return LoadSettingsFor<T>(TenantID, user.Id);
|
||||
}
|
||||
if (data.SequenceEqual(defaultData))
|
||||
{
|
||||
var strategy = webstudioDbContext.Database.CreateExecutionStrategy();
|
||||
|
||||
public T LoadForDefaultTenant<T>() where T : class, ISettings<T>
|
||||
{
|
||||
return LoadForTenant<T>(Tenant.DefaultTenant);
|
||||
}
|
||||
strategy.Execute(() =>
|
||||
{
|
||||
using var tr = webstudioDbContext.Database.BeginTransaction();
|
||||
// remove default settings
|
||||
var s = webstudioDbContext.WebstudioSettings
|
||||
.Where(r => r.Id == settings.ID)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.Where(r => r.UserId == userId)
|
||||
.FirstOrDefault();
|
||||
|
||||
public T LoadForTenant<T>(int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
return LoadSettings<T>(tenantId);
|
||||
}
|
||||
if (s != null)
|
||||
{
|
||||
webstudioDbContext.WebstudioSettings.Remove(s);
|
||||
}
|
||||
|
||||
public virtual bool Save<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveSettings(data, TenantID);
|
||||
}
|
||||
webstudioDbContext.SaveChanges();
|
||||
|
||||
public bool SaveForCurrentUser<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveForUser(data, CurrentUserID);
|
||||
}
|
||||
tr.Commit();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = new DbWebstudioSettings
|
||||
{
|
||||
Id = settings.ID,
|
||||
UserId = userId,
|
||||
TenantId = tenantId,
|
||||
Data = data
|
||||
};
|
||||
|
||||
public bool SaveForUser<T>(T data, Guid userId) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveSettingsFor(data, TenantID, userId);
|
||||
}
|
||||
webstudioDbContext.AddOrUpdate(webstudioDbContext.WebstudioSettings, s);
|
||||
|
||||
public bool SaveForUser<T>(T data, UserInfo user) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveSettingsFor(data, TenantID, user.Id);
|
||||
}
|
||||
webstudioDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public bool SaveForDefaultTenant<T>(T data) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveForTenant(data, Tenant.DefaultTenant);
|
||||
}
|
||||
_dbSettingsManagerCache.Remove(key);
|
||||
|
||||
public bool SaveForTenant<T>(T data, int tenantId) where T : class, ISettings<T>
|
||||
{
|
||||
return SaveSettings(data, tenantId);
|
||||
}
|
||||
_cache.Insert(key, settings, _expirationTimeout);
|
||||
|
||||
public void ClearCache<T>() where T : class, ISettings<T>
|
||||
{
|
||||
ClearCache<T>(TenantID);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorSaveSettingsFor(ex);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private T Deserialize<T>(string data)
|
||||
|
@ -227,7 +227,8 @@ public class EFUserService : IUserService
|
||||
if (sortBy == "type")
|
||||
{
|
||||
var q1 = from user in q
|
||||
join userGroup in userDbContext.UserGroups.Where(g => !g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID))
|
||||
join userGroup in userDbContext.UserGroups.Where(g => !g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID
|
||||
|| g.UserGroupId == Users.Constants.GroupCollaborator.ID))
|
||||
on user.Id equals userGroup.Userid into joinedGroup
|
||||
from @group in joinedGroup.DefaultIfEmpty()
|
||||
select new { user, @group };
|
||||
@ -235,12 +236,18 @@ public class EFUserService : IUserService
|
||||
if (sortOrderAsc)
|
||||
{
|
||||
q = q1.OrderBy(r => r.user.ActivationStatus == EmployeeActivationStatus.Pending)
|
||||
.ThenBy(r => r.group != null && r.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 : r.group == null ? 2 : 3).Select(r => r.user);
|
||||
.ThenBy(r => r.group == null ? 2 :
|
||||
r.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 :
|
||||
r.group.UserGroupId == Users.Constants.GroupCollaborator.ID ? 3 : 4)
|
||||
.Select(r => r.user);
|
||||
}
|
||||
else
|
||||
{
|
||||
q = q1.OrderBy(r => r.user.ActivationStatus == EmployeeActivationStatus.Pending)
|
||||
.ThenByDescending(u => u.group != null && u.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 : u.group == null ? 2 : 3).Select(r => r.user);
|
||||
.ThenByDescending(u => u.group == null ? 2 :
|
||||
u.group.UserGroupId == Users.Constants.GroupAdmin.ID ? 1 :
|
||||
u.group.UserGroupId == Users.Constants.GroupCollaborator.ID ? 3 : 4)
|
||||
.Select(r => r.user);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -300,33 +307,29 @@ public class EFUserService : IUserService
|
||||
using var userDbContext = _dbContextFactory.CreateDbContext();
|
||||
using var tr = userDbContext.Database.BeginTransaction();
|
||||
|
||||
userDbContext.Acl.RemoveRange(userDbContext.Acl.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Subject)));
|
||||
userDbContext.Subscriptions.RemoveRange(userDbContext.Subscriptions.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
|
||||
userDbContext.SubscriptionMethods.RemoveRange(userDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
|
||||
userDbContext.Acl.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Subject)).ExecuteDelete();
|
||||
userDbContext.Subscriptions.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)).ExecuteDelete();
|
||||
userDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)).ExecuteDelete();
|
||||
|
||||
var userGroups = userDbContext.UserGroups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.UserGroupId));
|
||||
var groups = userDbContext.Groups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Id));
|
||||
|
||||
if (immediate)
|
||||
{
|
||||
userDbContext.UserGroups.RemoveRange(userGroups);
|
||||
userDbContext.Groups.RemoveRange(groups);
|
||||
userGroups.ExecuteDelete();
|
||||
groups.ExecuteDelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var ug in userGroups)
|
||||
{
|
||||
ug.Removed = true;
|
||||
ug.LastModified = DateTime.UtcNow;
|
||||
}
|
||||
foreach (var g in groups)
|
||||
{
|
||||
g.Removed = true;
|
||||
g.LastModified = DateTime.UtcNow;
|
||||
}
|
||||
userGroups.ExecuteUpdate(ug => ug
|
||||
.SetProperty(p => p.Removed, true)
|
||||
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
||||
|
||||
groups.ExecuteUpdate(g => g
|
||||
.SetProperty(p => p.Removed, true)
|
||||
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
||||
}
|
||||
|
||||
userDbContext.SaveChanges();
|
||||
tr.Commit();
|
||||
});
|
||||
}
|
||||
@ -346,10 +349,10 @@ public class EFUserService : IUserService
|
||||
using var userDbContext = _dbContextFactory.CreateDbContext();
|
||||
using var tr = userDbContext.Database.BeginTransaction();
|
||||
|
||||
userDbContext.Acl.RemoveRange(userDbContext.Acl.Where(r => r.Tenant == tenant && r.Subject == id));
|
||||
userDbContext.Subscriptions.RemoveRange(userDbContext.Subscriptions.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
|
||||
userDbContext.SubscriptionMethods.RemoveRange(userDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
|
||||
userDbContext.Photos.RemoveRange(userDbContext.Photos.Where(r => r.Tenant == tenant && r.UserId == id));
|
||||
userDbContext.Acl.Where(r => r.Tenant == tenant && r.Subject == id).ExecuteDelete();
|
||||
userDbContext.Subscriptions.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()).ExecuteDelete();
|
||||
userDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()).ExecuteDelete();
|
||||
userDbContext.Photos.Where(r => r.Tenant == tenant && r.UserId == id).ExecuteDelete();
|
||||
|
||||
var userGroups = userDbContext.UserGroups.Where(r => r.Tenant == tenant && r.Userid == id);
|
||||
var users = userDbContext.Users.Where(r => r.Tenant == tenant && r.Id == id);
|
||||
@ -357,29 +360,24 @@ public class EFUserService : IUserService
|
||||
|
||||
if (immediate)
|
||||
{
|
||||
userDbContext.UserGroups.RemoveRange(userGroups);
|
||||
userDbContext.Users.RemoveRange(users);
|
||||
userDbContext.UserSecurity.RemoveRange(userSecurity);
|
||||
userGroups.ExecuteDelete();
|
||||
users.ExecuteDelete();
|
||||
userSecurity.ExecuteDelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var ug in userGroups)
|
||||
{
|
||||
ug.Removed = true;
|
||||
ug.LastModified = DateTime.UtcNow;
|
||||
}
|
||||
userGroups.ExecuteUpdate(ug => ug
|
||||
.SetProperty(p => p.Removed, true)
|
||||
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
u.Removed = true;
|
||||
u.Status = EmployeeStatus.Terminated;
|
||||
u.TerminatedDate = DateTime.UtcNow;
|
||||
u.LastModified = DateTime.UtcNow;
|
||||
}
|
||||
users.ExecuteUpdate(ug => ug
|
||||
.SetProperty(p => p.Removed, true)
|
||||
.SetProperty(p => p.LastModified, DateTime.UtcNow)
|
||||
.SetProperty(p => p.TerminatedDate, DateTime.UtcNow)
|
||||
.SetProperty(p => p.Status, EmployeeStatus.Terminated)
|
||||
);
|
||||
}
|
||||
|
||||
userDbContext.SaveChanges();
|
||||
|
||||
tr.Commit();
|
||||
});
|
||||
}
|
||||
@ -402,16 +400,15 @@ public class EFUserService : IUserService
|
||||
var userGroups = userDbContext.UserGroups.Where(r => r.Tenant == tenant && r.Userid == userId && r.UserGroupId == groupId && r.RefType == refType);
|
||||
if (immediate)
|
||||
{
|
||||
userDbContext.UserGroups.RemoveRange(userGroups);
|
||||
userGroups.ExecuteDelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var u in userGroups)
|
||||
{
|
||||
u.LastModified = DateTime.UtcNow;
|
||||
u.Removed = true;
|
||||
}
|
||||
userGroups.ExecuteUpdate(ug => ug
|
||||
.SetProperty(p => p.Removed, true)
|
||||
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
||||
}
|
||||
|
||||
var user = userDbContext.Users.First(r => r.Tenant == tenant && r.Id == userId);
|
||||
user.LastModified = DateTime.UtcNow;
|
||||
userDbContext.SaveChanges();
|
||||
@ -749,4 +746,4 @@ public class DbUserSecurity
|
||||
{
|
||||
public User User { get; set; }
|
||||
public UserSecurity UserSecurity { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ public class HostedSolution
|
||||
internal UserFormatter UserFormatter { get; set; }
|
||||
internal TenantManager ClientTenantManager { get; set; }
|
||||
internal TenantUtil TenantUtil { get; set; }
|
||||
internal DbSettingsManager SettingsManager { get; set; }
|
||||
internal SettingsManager SettingsManager { get; set; }
|
||||
internal CoreSettings CoreSettings { get; set; }
|
||||
|
||||
public string Region { get; private set; }
|
||||
@ -51,7 +51,7 @@ public class HostedSolution
|
||||
UserFormatter userFormatter,
|
||||
TenantManager clientTenantManager,
|
||||
TenantUtil tenantUtil,
|
||||
DbSettingsManager settingsManager,
|
||||
SettingsManager settingsManager,
|
||||
CoreSettings coreSettings)
|
||||
{
|
||||
TenantService = tenantService;
|
||||
@ -196,9 +196,9 @@ public class HostedSolution
|
||||
return null;
|
||||
}
|
||||
|
||||
var tenantSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, Guid.Empty);
|
||||
var tenantSettings = SettingsManager.Load<TenantCookieSettings>(tenantId, Guid.Empty);
|
||||
var expires = tenantSettings.IsDefault() ? DateTime.UtcNow.AddYears(1) : DateTime.UtcNow.AddMinutes(tenantSettings.LifeTime);
|
||||
var userSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, user.Id);
|
||||
var userSettings = SettingsManager.Load<TenantCookieSettings>(tenantId, user.Id);
|
||||
|
||||
return cookieStorage.EncryptCookie(tenantId, user.Id, tenantSettings.Index, expires, userSettings.Index, 0);
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ namespace ASC.Core.Common.Log;
|
||||
internal static partial class DbSettingsManagerLogger
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "SaveSettingsFor")]
|
||||
public static partial void ErrorSaveSettingsFor(this ILogger<DbSettingsManager> logger, Exception exception);
|
||||
public static partial void ErrorSaveSettingsFor(this ILogger<SettingsManager> logger, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "LoadSettingsFor")]
|
||||
public static partial void ErrorLoadSettingsFor(this ILogger<DbSettingsManager> logger, Exception exception);
|
||||
public static partial void ErrorLoadSettingsFor(this ILogger<SettingsManager> logger, Exception exception);
|
||||
}
|
||||
|
@ -445,7 +445,8 @@ public enum MessageAction
|
||||
DocumentsForcesave = 5049,
|
||||
DocumentsStoreForcesave = 5048,
|
||||
DocumentsUploadingFormatsSettingsUpdated = 5033,
|
||||
DocumentsExternalShareSettingsUpdated = 5069, // last
|
||||
DocumentsExternalShareSettingsUpdated = 5069,
|
||||
DocumentsKeepNewFileNameSettingsUpdated = 5083, // last
|
||||
|
||||
FileConverted = 5035,
|
||||
|
||||
|
@ -71,24 +71,18 @@ public class TelegramDao
|
||||
{
|
||||
using var dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var toRemove = dbContext.Users
|
||||
dbContext.Users
|
||||
.Where(r => r.PortalUserId == userId)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.ToList();
|
||||
|
||||
dbContext.Users.RemoveRange(toRemove);
|
||||
dbContext.SaveChanges();
|
||||
.ExecuteDelete();
|
||||
}
|
||||
|
||||
public void Delete(long telegramId)
|
||||
{
|
||||
using var dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var toRemove = dbContext.Users
|
||||
dbContext.Users
|
||||
.Where(r => r.TelegramUserId == telegramId)
|
||||
.ToList();
|
||||
|
||||
dbContext.Users.RemoveRange(toRemove);
|
||||
dbContext.SaveChanges();
|
||||
.ExecuteDelete();
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,36 @@
|
||||
// (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.Core.Common.Quota.Features;
|
||||
|
||||
public class CountRoomAdminFeature : TenantQuotaFeatureCount
|
||||
{
|
||||
public override bool Paid { get => true; }
|
||||
public override string Name { get => "manager"; }
|
||||
public CountRoomAdminFeature(TenantQuota tenantQuota) : base(tenantQuota)
|
||||
{
|
||||
}
|
||||
// (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.Core.Common.Quota.Features;
|
||||
|
||||
public class CountPaidUserFeature : TenantQuotaFeatureCount
|
||||
{
|
||||
public override bool Paid { get => true; }
|
||||
public override string Name { get => "manager"; }
|
||||
public CountPaidUserFeature(TenantQuota tenantQuota) : base(tenantQuota)
|
||||
{
|
||||
}
|
||||
}
|
@ -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 Constants = ASC.Common.Security.Authorizing.Constants;
|
||||
|
||||
namespace ASC.Core.Security.Authorizing;
|
||||
|
||||
[Scope]
|
||||
@ -50,6 +52,11 @@ class RoleProvider : IRoleProvider
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
if (roles.Any(r => r.ID == Constants.Collaborator.ID || r.ID == Constants.User.ID))
|
||||
{
|
||||
roles = roles.Where(r => r.ID != Constants.RoomAdmin.ID).ToList();
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
@ -75,4 +82,4 @@ class RoleProvider : IRoleProvider
|
||||
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,23 +31,30 @@ namespace ASC.Core.Common.Security;
|
||||
|
||||
public static class Security
|
||||
{
|
||||
public static readonly Dictionary<Guid, Dictionary<Guid, HashSet<Rule>>> Rules = new Dictionary<Guid, Dictionary<Guid, HashSet<Rule>>>
|
||||
public static readonly Dictionary<Guid, Dictionary<Guid, HashSet<Rule>>> Rules = new()
|
||||
{
|
||||
{
|
||||
Constants.RoomAdmin.ID, new Dictionary<Guid, HashSet<Rule>>()
|
||||
Constants.RoomAdmin.ID, new Dictionary<Guid, HashSet<Rule>>
|
||||
{
|
||||
{
|
||||
Constants.User.ID, new HashSet<Rule>()
|
||||
Constants.User.ID, new HashSet<Rule>
|
||||
{
|
||||
new Rule(UserConstants.Action_EditGroups.ID, Constants.User),
|
||||
new Rule(UserConstants.Action_AddRemoveUser.ID),
|
||||
new(UserConstants.Action_EditGroups.ID, Constants.User),
|
||||
new(UserConstants.Action_AddRemoveUser.ID),
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.RoomAdmin.ID, new HashSet<Rule>()
|
||||
Constants.RoomAdmin.ID, new HashSet<Rule>
|
||||
{
|
||||
new Rule(UserConstants.Action_EditGroups.ID, Constants.User),
|
||||
new Rule(UserConstants.Action_AddRemoveUser.ID),
|
||||
new(UserConstants.Action_EditGroups.ID, Constants.User),
|
||||
new(UserConstants.Action_AddRemoveUser.ID),
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.Collaborator.ID, new HashSet<Rule>
|
||||
{
|
||||
new(UserConstants.Action_EditGroups.ID, Constants.Collaborator),
|
||||
new(UserConstants.Action_AddRemoveUser.ID),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,29 +24,44 @@
|
||||
// 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 AuthConstants = ASC.Common.Security.Authorizing.Constants;
|
||||
|
||||
namespace ASC.Core.Common.Security;
|
||||
|
||||
public class UserGroupObject : SecurityObject
|
||||
{
|
||||
private ISubject User { get; set; }
|
||||
private Guid GroupId { get; set; }
|
||||
private readonly Guid _groupId;
|
||||
|
||||
public UserGroupObject(ISubject user, Guid groupId)
|
||||
{
|
||||
SecurityId = user.ID;
|
||||
User = user;
|
||||
GroupId = groupId;
|
||||
_groupId = groupId;
|
||||
ObjectType = typeof(UserGroupObject);
|
||||
FullId = $"{ObjectType.FullName}|{User.ID}|{GroupId}";
|
||||
FullId = $"{ObjectType.FullName}|{user.ID}|{_groupId}";
|
||||
}
|
||||
|
||||
protected override IEnumerable<IRole> GetTargetRoles(IRoleProvider roleProvider)
|
||||
{
|
||||
return roleProvider.GetRoles(User);
|
||||
if (_groupId == Users.Constants.GroupAdmin.ID)
|
||||
{
|
||||
return new[] { AuthConstants.DocSpaceAdmin };
|
||||
}
|
||||
|
||||
if (_groupId == Users.Constants.GroupUser.ID)
|
||||
{
|
||||
return new[] { AuthConstants.User };
|
||||
}
|
||||
|
||||
if (_groupId == Users.Constants.GroupCollaborator.ID)
|
||||
{
|
||||
return new[] { AuthConstants.Collaborator };
|
||||
}
|
||||
|
||||
return Array.Empty<IRole>();
|
||||
}
|
||||
|
||||
protected override IRuleData GetRuleData()
|
||||
{
|
||||
return new Role(GroupId, "ruleData");
|
||||
return new Role(_groupId, "ruleData");
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@ public class UserSecurityProvider : SecurityObject
|
||||
{
|
||||
EmployeeType.DocSpaceAdmin => new[] { AuthConstants.DocSpaceAdmin },
|
||||
EmployeeType.RoomAdmin => new[] { AuthConstants.RoomAdmin },
|
||||
EmployeeType.Collaborator => new[] { AuthConstants.Collaborator },
|
||||
EmployeeType.User => new[] { AuthConstants.User },
|
||||
_ => Array.Empty<IRole>(),
|
||||
};
|
||||
|
@ -72,7 +72,7 @@ public class TenantCookieSettingsHelper
|
||||
public TenantCookieSettings GetForTenant(int tenantId)
|
||||
{
|
||||
return IsVisibleSettings
|
||||
? _settingsManager.LoadForTenant<TenantCookieSettings>(tenantId)
|
||||
? _settingsManager.Load<TenantCookieSettings>(tenantId)
|
||||
: TenantCookieSettings.GetInstance();
|
||||
}
|
||||
|
||||
@ -83,20 +83,20 @@ public class TenantCookieSettingsHelper
|
||||
return;
|
||||
}
|
||||
|
||||
_settingsManager.SaveForTenant(settings ?? TenantCookieSettings.GetInstance(), tenantId);
|
||||
_settingsManager.Save(settings ?? TenantCookieSettings.GetInstance(), tenantId);
|
||||
}
|
||||
|
||||
public TenantCookieSettings GetForUser(Guid userId)
|
||||
{
|
||||
return IsVisibleSettings
|
||||
? _settingsManager.LoadForUser<TenantCookieSettings>(userId)
|
||||
? _settingsManager.Load<TenantCookieSettings>(userId)
|
||||
: TenantCookieSettings.GetInstance();
|
||||
}
|
||||
|
||||
public TenantCookieSettings GetForUser(int tenantId, Guid userId)
|
||||
{
|
||||
return IsVisibleSettings
|
||||
? _settingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, userId)
|
||||
? _settingsManager.Load<TenantCookieSettings>(tenantId, userId)
|
||||
: TenantCookieSettings.GetInstance();
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public class TenantCookieSettingsHelper
|
||||
return;
|
||||
}
|
||||
|
||||
_settingsManager.SaveForUser(settings ?? TenantCookieSettings.GetInstance(), userId);
|
||||
_settingsManager.Save(settings ?? TenantCookieSettings.GetInstance(), userId);
|
||||
}
|
||||
|
||||
public DateTime GetExpiresTime(int tenantId)
|
||||
|
@ -90,11 +90,11 @@ public class TenantQuota : IMapFrom<DbQuota>
|
||||
set => _countUserFeature.Value = value;
|
||||
}
|
||||
|
||||
private readonly CountRoomAdminFeature _countRoomAdminFeature;
|
||||
private readonly CountPaidUserFeature _countPaidUserFeature;
|
||||
public int CountRoomAdmin
|
||||
{
|
||||
get => _countRoomAdminFeature.Value;
|
||||
set => _countRoomAdminFeature.Value = value;
|
||||
get => _countPaidUserFeature.Value;
|
||||
set => _countPaidUserFeature.Value = value;
|
||||
}
|
||||
|
||||
private readonly UsersInRoomFeature _usersInRoomFeature;
|
||||
@ -221,7 +221,7 @@ public class TenantQuota : IMapFrom<DbQuota>
|
||||
_featuresList = new List<string>();
|
||||
|
||||
_countUserFeature = new CountUserFeature(this) { Order = 1 };
|
||||
_countRoomAdminFeature = new CountRoomAdminFeature(this);
|
||||
_countPaidUserFeature = new CountPaidUserFeature(this);
|
||||
_usersInRoomFeature = new UsersInRoomFeature(this) { Order = 8 };
|
||||
_countRoomFeature = new CountRoomFeature(this) { Order = 2 };
|
||||
_maxTotalSizeFeature = new MaxTotalSizeFeature(this);
|
||||
@ -245,7 +245,7 @@ public class TenantQuota : IMapFrom<DbQuota>
|
||||
TenantQuotaFeatures = new List<TenantQuotaFeature>
|
||||
{
|
||||
_countUserFeature,
|
||||
_countRoomAdminFeature,
|
||||
_countPaidUserFeature,
|
||||
_usersInRoomFeature,
|
||||
_countRoomFeature,
|
||||
_maxTotalSizeFeature,
|
||||
|
@ -24,9 +24,9 @@
|
||||
// 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 Action = ASC.Common.Security.Authorizing.Action;
|
||||
using AuthConst = ASC.Common.Security.Authorizing.Constants;
|
||||
|
||||
using Action = ASC.Common.Security.Authorizing.Action;
|
||||
using AuthConst = ASC.Common.Security.Authorizing.Constants;
|
||||
|
||||
namespace ASC.Core.Users;
|
||||
|
||||
[Singletone]
|
||||
@ -59,7 +59,7 @@ public sealed class Constants
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
#region system group and category groups
|
||||
#region system group and category groups
|
||||
|
||||
public static readonly Guid SysGroupCategoryId = new Guid("{7717039D-FBE9-45ad-81C1-68A1AA10CE1F}");
|
||||
|
||||
@ -87,12 +87,19 @@ public sealed class Constants
|
||||
Name = AuthConst.DocSpaceAdmin.Name,
|
||||
};
|
||||
|
||||
public static readonly GroupInfo GroupCollaborator = new(SysGroupCategoryId)
|
||||
{
|
||||
ID = AuthConst.Collaborator.ID,
|
||||
Name = AuthConst.Collaborator.Name,
|
||||
};
|
||||
|
||||
public static readonly GroupInfo[] BuildinGroups = new[]
|
||||
{
|
||||
GroupEveryone,
|
||||
GroupUser,
|
||||
GroupManager,
|
||||
GroupAdmin,
|
||||
{
|
||||
GroupEveryone,
|
||||
GroupUser,
|
||||
GroupManager,
|
||||
GroupAdmin,
|
||||
GroupCollaborator,
|
||||
};
|
||||
|
||||
public static readonly UserInfo LostUser = new UserInfo
|
||||
@ -119,10 +126,10 @@ public sealed class Constants
|
||||
Name = "Unknown"
|
||||
};
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region authorization rules module to work with users
|
||||
#region authorization rules module to work with users
|
||||
|
||||
public static readonly Action Action_EditUser = new Action(
|
||||
new Guid("{EF5E6790-F346-4b6e-B662-722BC28CB0DB}"),
|
||||
@ -136,5 +143,5 @@ public sealed class Constants
|
||||
new Guid("{1D4FEEAC-0BF3-4aa9-B096-6D6B104B79B5}"),
|
||||
"Edit categories and groups");
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -40,7 +40,12 @@ public static class UserExtensions
|
||||
|
||||
public static bool IsMe(this UserInfo ui, AuthContext authContext)
|
||||
{
|
||||
return ui != null && ui.Id == authContext.CurrentAccount.ID;
|
||||
return IsMe(ui, authContext.CurrentAccount.ID);
|
||||
}
|
||||
|
||||
public static bool IsMe(this UserInfo user, Guid id)
|
||||
{
|
||||
return user != null && user.Id == id;
|
||||
}
|
||||
|
||||
public static bool IsDocSpaceAdmin(this UserManager userManager, Guid id)
|
||||
@ -65,6 +70,17 @@ public static class UserExtensions
|
||||
return ui != null && userManager.IsUserInGroup(ui.Id, Constants.GroupUser.ID);
|
||||
}
|
||||
|
||||
public static bool IsCollaborator(this UserManager userManager, UserInfo userInfo)
|
||||
{
|
||||
return userInfo != null && userManager.IsUserInGroup(userInfo.Id, Constants.GroupCollaborator.ID);
|
||||
}
|
||||
|
||||
public static bool IsCollaborator(this UserManager userManager, Guid id)
|
||||
{
|
||||
var userInfo = userManager.GetUsers(id);
|
||||
return userManager.IsCollaborator(userInfo);
|
||||
}
|
||||
|
||||
public static bool IsOutsider(this UserManager userManager, Guid id)
|
||||
{
|
||||
return userManager.IsUser(id) && id == Constants.OutsideUser.Id;
|
||||
@ -98,7 +114,15 @@ public static class UserExtensions
|
||||
|
||||
public static EmployeeType GetUserType(this UserManager userManager, Guid id)
|
||||
{
|
||||
return userManager.IsDocSpaceAdmin(id) ? EmployeeType.DocSpaceAdmin : userManager.IsUser(id) ? EmployeeType.User : EmployeeType.RoomAdmin;
|
||||
if (userManager.GetUsers(id).Equals(Constants.LostUser))
|
||||
{
|
||||
return EmployeeType.User;
|
||||
}
|
||||
|
||||
return userManager.IsDocSpaceAdmin(id) ? EmployeeType.DocSpaceAdmin :
|
||||
userManager.IsUser(id) ? EmployeeType.User :
|
||||
userManager.IsCollaborator(id) ? EmployeeType.Collaborator :
|
||||
EmployeeType.RoomAdmin;
|
||||
}
|
||||
|
||||
private const string _extMobPhone = "extmobphone";
|
||||
@ -146,4 +170,4 @@ public static class UserExtensions
|
||||
|
||||
ui.ContactsList = newContacts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,10 +115,7 @@ public class BackupRepository : IBackupRepository
|
||||
public void DeleteBackupSchedule(int tenantId)
|
||||
{
|
||||
using var backupContext = _dbContextFactory.CreateDbContext();
|
||||
var shedule = backupContext.Schedules.AsQueryable().Where(s => s.TenantId == tenantId).ToList();
|
||||
|
||||
backupContext.Schedules.RemoveRange(shedule);
|
||||
backupContext.SaveChanges();
|
||||
backupContext.Schedules.Where(s => s.TenantId == tenantId).ExecuteDelete();
|
||||
}
|
||||
|
||||
public List<BackupSchedule> GetBackupSchedules()
|
||||
|
@ -40,7 +40,7 @@ public class Helpers
|
||||
ConfigurationConstants.CoreSystem.ID,
|
||||
ConfigurationConstants.Guest.ID,
|
||||
UserConstants.LostUser.Id
|
||||
};
|
||||
};
|
||||
|
||||
private readonly Guid[] _systemGroups = new[]
|
||||
{
|
||||
@ -50,6 +50,7 @@ public class Helpers
|
||||
UserConstants.GroupEveryone.ID,
|
||||
UserConstants.GroupUser.ID,
|
||||
UserConstants.GroupManager.ID,
|
||||
UserConstants.GroupCollaborator.ID,
|
||||
new Guid("{EA942538-E68E-4907-9394-035336EE0BA8}"), //community product
|
||||
new Guid("{1e044602-43b5-4d79-82f3-fd6208a11960}"), //projects product
|
||||
new Guid("{6743007C-6F95-4d20-8C88-A8601CE5E76D}"), //crm product
|
||||
@ -59,7 +60,7 @@ public class Helpers
|
||||
new Guid("{32D24CB5-7ECE-4606-9C94-19216BA42086}"), //calendar product
|
||||
new Guid("{37620AE5-C40B-45ce-855A-39DD7D76A1FA}"), //birthdays product
|
||||
new Guid("{BF88953E-3C43-4850-A3FB-B1E43AD53A3E}") //talk product
|
||||
};
|
||||
};
|
||||
|
||||
public Helpers(InstanceCrypto instanceCrypto)
|
||||
{
|
||||
|
@ -117,14 +117,17 @@ public class CommonChunkedUploadSession : ICloneable
|
||||
switch (value.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
newItems.Add(item.Key, item.Value.ToString());
|
||||
newItems.Add(item.Key, item.Value.ToString());
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
newItems.Add(item.Key, Int32.Parse(item.Value.ToString()));
|
||||
break;
|
||||
case JsonValueKind.Array:
|
||||
newItems.Add(item.Key, value.EnumerateArray().Select(o => o.ToString()).ToList());
|
||||
break;
|
||||
newItems.Add(item.Key, value.EnumerateArray().Select(o => o.ToString()).ToList());
|
||||
break;
|
||||
case JsonValueKind.Object:
|
||||
newItems.Add(item.Key, JsonSerializer.Deserialize<Dictionary<int, string>>(item.Value.ToString()));
|
||||
break;
|
||||
default:
|
||||
newItems.Add(item.Key, item.Value);
|
||||
break;
|
||||
|
@ -63,13 +63,13 @@ public class BaseStorageSettingsListener
|
||||
|
||||
var scopeClass = scope.ServiceProvider.GetService<BaseStorageSettingsListenerScope>();
|
||||
var (storageSettingsHelper, settingsManager) = scopeClass;
|
||||
var settings = settingsManager.LoadForTenant<StorageSettings>(i.TenantId);
|
||||
var settings = settingsManager.Load<StorageSettings>(i.TenantId);
|
||||
if (i.Name == settings.Module)
|
||||
{
|
||||
storageSettingsHelper.Clear(settings);
|
||||
}
|
||||
|
||||
var cdnSettings = settingsManager.LoadForTenant<CdnStorageSettings>(i.TenantId);
|
||||
var cdnSettings = settingsManager.Load<CdnStorageSettings>(i.TenantId);
|
||||
if (i.Name == cdnSettings.Module)
|
||||
{
|
||||
storageSettingsHelper.Clear(cdnSettings);
|
||||
|
@ -155,7 +155,7 @@ public class StorageFactory
|
||||
throw new InvalidOperationException("config section not found");
|
||||
}
|
||||
|
||||
var settings = _settingsManager.LoadForTenant<StorageSettings>(tenant.Value);
|
||||
var settings = _settingsManager.Load<StorageSettings>(tenant.Value);
|
||||
//TODO:GetStoreAndCache
|
||||
return GetDataStore(tenantPath, module, _storageSettingsHelper.DataStoreConsumer(settings), controller, region);
|
||||
}
|
||||
|
@ -89,8 +89,8 @@ public class S3ZipWriteOperator : IDataWriteOperator
|
||||
{
|
||||
var fs = _fileStream;
|
||||
_fileStream = null;
|
||||
Upload(fs);
|
||||
Computehash(fs, false);
|
||||
Upload(fs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ public class S3ZipWriteOperator : IDataWriteOperator
|
||||
stream.Position = 0;
|
||||
var buffer = new byte[_sessionHolder.MaxChunkUploadSize];
|
||||
int bytesRead;
|
||||
while ((bytesRead = _fileStream.Read(buffer, 0, (int)_sessionHolder.MaxChunkUploadSize)) > 0)
|
||||
while ((bytesRead = stream.Read(buffer, 0, (int)_sessionHolder.MaxChunkUploadSize)) > 0)
|
||||
{
|
||||
_sha.TransformBlock(buffer, 0, bytesRead, buffer, 0);
|
||||
}
|
||||
@ -134,12 +134,13 @@ public class S3ZipWriteOperator : IDataWriteOperator
|
||||
_tarOutputStream.Close();
|
||||
_tarOutputStream.Dispose();
|
||||
|
||||
Computehash(_fileStream, true);
|
||||
Upload(_fileStream);
|
||||
|
||||
Task.WaitAll(_tasks.ToArray());
|
||||
|
||||
StoragePath = await _sessionHolder.FinalizeAsync(_chunkedUploadSession);
|
||||
|
||||
Computehash(_fileStream, true);
|
||||
Hash = BitConverter.ToString(_sha.Hash).Replace("-", string.Empty);
|
||||
_sha.Dispose();
|
||||
|
||||
|
@ -154,11 +154,8 @@ public class FeedAggregateDataProvider
|
||||
using var feedDbContext = _dbContextFactory.CreateDbContext();
|
||||
using var tx = feedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
|
||||
|
||||
var aggregates = feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime);
|
||||
feedDbContext.FeedAggregates.RemoveRange(aggregates);
|
||||
|
||||
var users = feedDbContext.FeedUsers.Where(r => feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).Any(a => a.Id == r.FeedId));
|
||||
feedDbContext.FeedUsers.RemoveRange(users);
|
||||
feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).ExecuteDelete();
|
||||
feedDbContext.FeedUsers.Where(r => feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).Any(a => a.Id == r.FeedId)).ExecuteDelete();
|
||||
|
||||
tx.Commit();
|
||||
});
|
||||
@ -310,13 +307,8 @@ public class FeedAggregateDataProvider
|
||||
using var feedDbContext = _dbContextFactory.CreateDbContext();
|
||||
using var tx = feedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
|
||||
|
||||
var aggregates = feedDbContext.FeedAggregates.Where(r => r.Id == id);
|
||||
feedDbContext.FeedAggregates.RemoveRange(aggregates);
|
||||
|
||||
var users = feedDbContext.FeedUsers.Where(r => r.FeedId == id);
|
||||
feedDbContext.FeedUsers.RemoveRange(users);
|
||||
|
||||
feedDbContext.SaveChanges();
|
||||
feedDbContext.FeedAggregates.Where(r => r.Id == id).ExecuteDelete();
|
||||
feedDbContext.FeedUsers.Where(r => r.FeedId == id).ExecuteDelete();
|
||||
|
||||
tx.Commit();
|
||||
});
|
||||
|
@ -57,16 +57,14 @@ public class IPRestrictionsRepository
|
||||
using var tenantDbContext = _dbContextManager.CreateDbContext();
|
||||
using var tx = tenantDbContext.Database.BeginTransaction();
|
||||
|
||||
var restrictions = tenantDbContext.TenantIpRestrictions.Where(r => r.Tenant == tenant).ToList();
|
||||
tenantDbContext.TenantIpRestrictions.RemoveRange(restrictions);
|
||||
tenantDbContext.SaveChanges();
|
||||
tenantDbContext.TenantIpRestrictions.Where(r => r.Tenant == tenant).ExecuteDelete();
|
||||
|
||||
var ipsList = ips.Select(r => new TenantIpRestrictions
|
||||
{
|
||||
Tenant = tenant,
|
||||
Ip = r.Ip,
|
||||
ForAdmin = r.ForAdmin
|
||||
|
||||
|
||||
});
|
||||
|
||||
tenantDbContext.TenantIpRestrictions.AddRange(ipsList);
|
||||
|
@ -69,7 +69,13 @@ public class DbWorker
|
||||
return objForCreate;
|
||||
}
|
||||
|
||||
var toAdd = new WebhooksConfig { TenantId = Tenant, Uri = uri, SecretKey = secretKey };
|
||||
var toAdd = new WebhooksConfig
|
||||
{
|
||||
TenantId = Tenant,
|
||||
Uri = uri,
|
||||
SecretKey = secretKey
|
||||
};
|
||||
|
||||
toAdd = await webhooksDbContext.AddOrUpdateAsync(r => r.WebhooksConfigs, toAdd);
|
||||
await webhooksDbContext.SaveChangesAsync();
|
||||
|
||||
|
@ -123,9 +123,9 @@ public class Startup
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
app.UseEndpoints(async endpoints =>
|
||||
{
|
||||
endpoints.MapCustom();
|
||||
await endpoints.MapCustomAsync();
|
||||
|
||||
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
|
@ -144,19 +144,20 @@ public class Startup
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
app.UseEndpoints( async endpoints =>
|
||||
{
|
||||
endpoints.MapCustom();
|
||||
await endpoints.MapCustomAsync();
|
||||
|
||||
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
|
||||
{
|
||||
Predicate = _ => true,
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name.Contains("self")
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -57,10 +57,7 @@ try
|
||||
|
||||
startup.ConfigureServices(builder.Services);
|
||||
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||||
{
|
||||
startup.ConfigureContainer(containerBuilder);
|
||||
});
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>(startup.ConfigureContainer);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
@ -57,10 +57,7 @@ try
|
||||
|
||||
startup.ConfigureServices(builder.Services);
|
||||
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||||
{
|
||||
startup.ConfigureContainer(containerBuilder);
|
||||
});
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>(startup.ConfigureContainer);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
@ -158,7 +158,7 @@ public class SearchSettingsHelper
|
||||
return true;
|
||||
}
|
||||
|
||||
var settings = _settingsManager.LoadForTenant<SearchSettings>(tenantId);
|
||||
var settings = _settingsManager.Load<SearchSettings>(tenantId);
|
||||
|
||||
return settings.IsEnabled(((ISearchItemDocument)_serviceProvider.GetService(t)).IndexName);
|
||||
}
|
||||
|
@ -85,15 +85,11 @@ public class NotifyCleanerService : BackgroundService
|
||||
{
|
||||
using var tx = dbContext.Database.BeginTransaction();
|
||||
|
||||
var info = dbContext.NotifyInfo.Where(r => r.ModifyDate < date && r.State == 4).ToList();
|
||||
var queue = dbContext.NotifyQueue.Where(r => r.CreationDate < date).ToList();
|
||||
dbContext.NotifyInfo.RemoveRange(info);
|
||||
dbContext.NotifyQueue.RemoveRange(queue);
|
||||
|
||||
dbContext.SaveChanges();
|
||||
var infoCount = dbContext.NotifyInfo.Where(r => r.ModifyDate < date && r.State == 4).ExecuteDelete();
|
||||
var queueCount = dbContext.NotifyQueue.Where(r => r.CreationDate < date).ExecuteDelete();
|
||||
tx.Commit();
|
||||
|
||||
_logger.InformationClearNotifyMessages(info.Count, queue.Count);
|
||||
_logger.InformationClearNotifyMessages(infoCount, queueCount);
|
||||
});
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
|
@ -69,6 +69,7 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script src="/static/scripts/browserDetector.js"></script>
|
||||
<script>
|
||||
console.log("It's WEB CLIENT INIT");
|
||||
fetch("/static/scripts/config.json")
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"ResetApplicationDescription": "Authenticator application configuration will be reset.",
|
||||
"ResetApplicationTitle": "Reset application configuration"
|
||||
"ResetApplicationTitle": "Reset application configuration",
|
||||
"SuccessResetApplication": "Application settings for authentication have been successfully reset"
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
"Remove": "Remove",
|
||||
"RoleCommentator": "Commentator",
|
||||
"RoleCommentatorDescription": "Operations with existing files: viewing, commenting.",
|
||||
"RoleCollaboratorDescription": "Collaborators can create and edit files in the room, but can't create rooms, manage users, or access settings.",
|
||||
"RoleDocSpaceAdminDescription": "DocSpace admins can access DocSpace settings, manage and archive rooms, invite new users and assign roles below their level. All admins have access to the Personal section.",
|
||||
"RoleEditor": "Editor",
|
||||
"RoleEditorDescription": "Operations with existing files: viewing, editing, form filling, reviewing, commenting.",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"BackToParentFolderButton": "Вернуться в папку на уровень выше",
|
||||
"ByAuthor": "Автор",
|
||||
"ByCreation": "Создан",
|
||||
"ByErasure": "Стирание",
|
||||
"ByLastModified": "Изменен",
|
||||
"ByOwner": "владелец",
|
||||
"CollaborationRooms": "Совместное редактирование",
|
||||
@ -22,6 +23,7 @@
|
||||
"CopyItems": "Скопировано элементов: <strong>{{qty}}</strong>",
|
||||
"CreateRoom": "Создание комнаты",
|
||||
"CustomRooms": "Пользовательская",
|
||||
"DaysRemaining": "Дней осталось: {{daysRemaining}}",
|
||||
"Document": "Документ",
|
||||
"EditRoom": "Изменить комнату",
|
||||
"EmptyFile": "Пустой файл",
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"ResetApplicationDescription": "Настройки приложения для аутентификации будут сброшены.",
|
||||
"ResetApplicationTitle": "Сбросить настройки приложения"
|
||||
"ResetApplicationTitle": "Сбросить настройки приложения",
|
||||
"SuccessResetApplication": "Настройки приложения для аутентификации успешно сброшены"
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
"Remove": "Удалить",
|
||||
"RoleCommentator": "Комментатор",
|
||||
"RoleCommentatorDescription": "Операции с существующими файлами: просмотр, комментирование.",
|
||||
"RoleCollaboratorDescription": "Сотрудники могут создавать и редактировать файлы в комнате, но не могут создавать комнаты, управлять пользователями или получать доступ к настройкам.",
|
||||
"RoleDocSpaceAdminDescription": "Администраторы DocSpace могут получить доступ к настройкам DocSpace, управлять и архивировать комнаты, приглашать новых пользователей и назначать роли ниже своего уровня. Все администраторы имеют доступ к Личному разделу.",
|
||||
"RoleEditor": "Редактор",
|
||||
"RoleEditorDescription": "Операции с существующими файлами: просмотр, редактирование, заполнение форм, рецензирование, комментирование.",
|
||||
|
@ -55,7 +55,7 @@ const withLoader = (WrappedComponent) => (Loader) => {
|
||||
|
||||
return (!isEditor && firstLoad && !isGallery) ||
|
||||
!isLoaded ||
|
||||
(isMobile && inLoad) ||
|
||||
(isMobile && inLoad && !firstLoad) ||
|
||||
(isLoadingFilesFind && !Loader) ||
|
||||
!tReady ||
|
||||
!isInit ? (
|
||||
|
@ -517,7 +517,6 @@ const ShellWrapper = inject(({ auth, backup }) => {
|
||||
setSnackbarExist,
|
||||
socketHelper,
|
||||
setTheme,
|
||||
getWhiteLabelLogoUrls,
|
||||
whiteLabelLogoUrls,
|
||||
} = settingsStore;
|
||||
const isBase = settingsStore.theme.isBase;
|
||||
|
3
packages/client/src/bootstrap.js
vendored
3
packages/client/src/bootstrap.js
vendored
@ -2,7 +2,8 @@ import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
//import { registerSW } from "@docspace/common/sw/helper";
|
||||
const root = document.getElementById("root");
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
if (root) ReactDOM.render(<App />, root);
|
||||
|
||||
//registerSW();
|
||||
|
@ -154,6 +154,7 @@ const Items = ({
|
||||
startUpload,
|
||||
uploadEmptyFolders,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
isAdmin,
|
||||
myId,
|
||||
commonId,
|
||||
@ -169,6 +170,8 @@ const Items = ({
|
||||
|
||||
onHide,
|
||||
firstLoad,
|
||||
deleteAction,
|
||||
startDrag,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
data.forEach((elem) => {
|
||||
@ -263,7 +266,12 @@ const Items = ({
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!draggableItems || draggableItems.find((x) => x.id === item.id))
|
||||
if (
|
||||
!draggableItems ||
|
||||
draggableItems.find(
|
||||
(x) => x.id === item.id && x.isFolder === item.isFolder
|
||||
)
|
||||
)
|
||||
return false;
|
||||
|
||||
if (
|
||||
@ -278,7 +286,8 @@ const Items = ({
|
||||
(item.pathParts &&
|
||||
(item.pathParts[0] === myId || item.pathParts[0] === commonId)) ||
|
||||
item.rootFolderType === FolderType.USER ||
|
||||
item.rootFolderType === FolderType.COMMON
|
||||
item.rootFolderType === FolderType.COMMON ||
|
||||
(item.rootFolderType === FolderType.TRASH && startDrag)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@ -306,6 +315,18 @@ const Items = ({
|
||||
[moveDragItems, t]
|
||||
);
|
||||
|
||||
const onRemove = React.useCallback(() => {
|
||||
const translations = {
|
||||
deleteOperation: t("Translations:DeleteOperation"),
|
||||
deleteFromTrash: t("Translations:DeleteFromTrash"),
|
||||
deleteSelectedElem: t("Translations:DeleteSelectedElem"),
|
||||
FileRemoved: t("Files:FileRemoved"),
|
||||
FolderRemoved: t("Files:FolderRemoved"),
|
||||
};
|
||||
|
||||
deleteAction(translations);
|
||||
}, [deleteAction]);
|
||||
|
||||
const onEmptyTrashAction = () => {
|
||||
isMobile && onHide();
|
||||
setEmptyTrashDialogVisible(true);
|
||||
@ -335,7 +356,7 @@ const Items = ({
|
||||
getEndOfBlock={getEndOfBlock}
|
||||
showText={showText}
|
||||
onClick={onClick}
|
||||
onMoveTo={onMoveTo}
|
||||
onMoveTo={isTrash ? onRemove : onMoveTo}
|
||||
onBadgeClick={isTrash ? onEmptyTrashAction : onBadgeClick}
|
||||
showDragItems={showDragItems}
|
||||
showBadge={showBadge}
|
||||
@ -347,7 +368,8 @@ const Items = ({
|
||||
});
|
||||
|
||||
if (!firstLoad) items.splice(3, 0, <SettingsItem key="settings-item" />);
|
||||
if (!isVisitor) items.splice(3, 0, <AccountsItem key="accounts-item" />);
|
||||
if (!isVisitor && !isCollaborator)
|
||||
items.splice(3, 0, <AccountsItem key="accounts-item" />);
|
||||
|
||||
if (!isVisitor) items.splice(3, 0, <CatalogDivider key="other-header" />);
|
||||
else items.splice(2, 0, <CatalogDivider key="other-header" />);
|
||||
@ -401,9 +423,9 @@ export default inject(
|
||||
selection,
|
||||
dragging,
|
||||
setDragging,
|
||||
setStartDrag,
|
||||
trashIsEmpty,
|
||||
firstLoad,
|
||||
startDrag,
|
||||
} = filesStore;
|
||||
|
||||
const { startUpload } = uploadDataStore;
|
||||
@ -417,12 +439,17 @@ export default inject(
|
||||
} = treeFoldersStore;
|
||||
|
||||
const { id, pathParts, rootFolderType } = selectedFolderStore;
|
||||
const { moveDragItems, uploadEmptyFolders } = filesActionsStore;
|
||||
const {
|
||||
moveDragItems,
|
||||
uploadEmptyFolders,
|
||||
deleteAction,
|
||||
} = filesActionsStore;
|
||||
const { setEmptyTrashDialogVisible } = dialogsStore;
|
||||
|
||||
return {
|
||||
isAdmin: auth.isAdmin,
|
||||
isVisitor: auth.userStore.user.isVisitor,
|
||||
isCollaborator: auth.userStore.user.isCollaborator,
|
||||
myId: myFolderId,
|
||||
commonId: commonFolderId,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
@ -435,14 +462,15 @@ export default inject(
|
||||
draggableItems: dragging ? selection : null,
|
||||
dragging,
|
||||
setDragging,
|
||||
setStartDrag,
|
||||
moveDragItems,
|
||||
deleteAction,
|
||||
startUpload,
|
||||
uploadEmptyFolders,
|
||||
setEmptyTrashDialogVisible,
|
||||
trashIsEmpty,
|
||||
rootFolderType,
|
||||
firstLoad,
|
||||
startDrag,
|
||||
};
|
||||
}
|
||||
)(withTranslation(["Files", "Common", "Translations"])(observer(Items)));
|
||||
|
@ -86,54 +86,15 @@ const ArticleBodyContent = (props) => {
|
||||
? RoomSearchArea.Archive
|
||||
: RoomSearchArea.Active;
|
||||
|
||||
fetchRooms(folderId, filter)
|
||||
.then(() => {
|
||||
const url = getCategoryUrl(
|
||||
folderId === archiveFolderId
|
||||
? CategoryType.Archive
|
||||
: CategoryType.Shared
|
||||
);
|
||||
|
||||
const filterParamsStr = filter.toUrlParams();
|
||||
|
||||
history.push(
|
||||
combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
homepage,
|
||||
`${url}?${filterParamsStr}`
|
||||
)
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
if (filesSection) {
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
hideLoader();
|
||||
}
|
||||
});
|
||||
fetchRooms(folderId, filter).finally(() => {
|
||||
if (filesSection) {
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
hideLoader();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fetchFiles(folderId, null, true, false)
|
||||
.then(() => {
|
||||
if (!filesSection) {
|
||||
const filter = FilesFilter.getDefault();
|
||||
|
||||
filter.folder = folderId;
|
||||
|
||||
const filterParamsStr = filter.toUrlParams();
|
||||
|
||||
const url = getCategoryUrl(categoryType, filter.folder);
|
||||
|
||||
const pathname = `${url}?${filterParamsStr}`;
|
||||
|
||||
history.push(
|
||||
combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
config.homepage,
|
||||
pathname
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => {
|
||||
if (filesSection) {
|
||||
|
@ -9,6 +9,7 @@ import ActionsPresentationReactSvgUrl from "PUBLIC_DIR/images/actions.presentati
|
||||
import CatalogFolderReactSvgUrl from "PUBLIC_DIR/images/catalog.folder.react.svg?url";
|
||||
import PersonAdminReactSvgUrl from "PUBLIC_DIR/images/person.admin.react.svg?url";
|
||||
import PersonManagerReactSvgUrl from "PUBLIC_DIR/images/person.manager.react.svg?url";
|
||||
import PersonReactSvgUrl from "PUBLIC_DIR/images/person.react.svg?url";
|
||||
import PersonUserReactSvgUrl from "PUBLIC_DIR/images/person.user.react.svg?url";
|
||||
import InviteAgainReactSvgUrl from "PUBLIC_DIR/images/invite.again.react.svg?url";
|
||||
import React from "react";
|
||||
@ -29,7 +30,7 @@ import { Events, EmployeeType } from "@docspace/common/constants";
|
||||
import { getMainButtonItems } from "SRC_DIR/helpers/plugins";
|
||||
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import styled from "styled-components";
|
||||
import styled, { css } from "styled-components";
|
||||
import Button from "@docspace/components/button";
|
||||
|
||||
import { resendInvitesAgain } from "@docspace/common/api/people";
|
||||
@ -38,30 +39,36 @@ const StyledButton = styled(Button)`
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
opacity: 1;
|
||||
opacity: ${(props) => (props.isDisabled ? 0.6 : 1)};
|
||||
|
||||
background-color: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent} !important;
|
||||
background: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
border: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
|
||||
:hover {
|
||||
background-color: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
opacity: 0.85;
|
||||
background: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
border: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
}
|
||||
${(props) =>
|
||||
!props.isDisabled &&
|
||||
css`
|
||||
:hover {
|
||||
background-color: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
opacity: 0.85;
|
||||
background: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
border: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
}
|
||||
|
||||
:active {
|
||||
background-color: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
background: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
border: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
opacity: 1;
|
||||
filter: brightness(90%);
|
||||
cursor: pointer;
|
||||
}
|
||||
:active {
|
||||
background-color: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
background: ${({ currentColorScheme }) =>
|
||||
currentColorScheme.main.accent};
|
||||
border: ${({ currentColorScheme }) => currentColorScheme.main.accent};
|
||||
opacity: 1;
|
||||
filter: brightness(90%);
|
||||
cursor: pointer;
|
||||
}
|
||||
`}
|
||||
|
||||
.button-content {
|
||||
color: ${({ currentColorScheme }) => currentColorScheme.text.accent};
|
||||
@ -113,6 +120,8 @@ const ArticleMainButtonContent = (props) => {
|
||||
setInvitePanelOptions,
|
||||
|
||||
mainButtonMobileVisible,
|
||||
|
||||
security,
|
||||
} = props;
|
||||
|
||||
const isAccountsPage = selectedTreeNode[0] === "accounts";
|
||||
@ -297,6 +306,15 @@ const ArticleMainButtonContent = (props) => {
|
||||
action: EmployeeType.User,
|
||||
key: "manager",
|
||||
},
|
||||
{
|
||||
id: "invite_room-collaborator",
|
||||
className: "main-button_drop-down",
|
||||
icon: PersonReactSvgUrl,
|
||||
label: t("Common:Collaborator"),
|
||||
onClick: onInvite,
|
||||
action: EmployeeType.Collaborator,
|
||||
key: "collaborator",
|
||||
},
|
||||
{
|
||||
id: "invite_user",
|
||||
className: "main-button_drop-down",
|
||||
@ -429,26 +447,27 @@ const ArticleMainButtonContent = (props) => {
|
||||
? t("Common:Invite")
|
||||
: t("Common:Actions");
|
||||
|
||||
const isDisabled =
|
||||
((!canCreate || (!canCreateFiles && !isRoomsFolder)) && !canInvite) ||
|
||||
isArchiveFolder;
|
||||
const isDisabled = isAccountsPage ? !canInvite : !security?.Create;
|
||||
|
||||
const isProfile = history.location.pathname === "/accounts/view/@self";
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMobileArticle ? (
|
||||
<>
|
||||
{!isArticleLoading && !isProfile && (canCreateFiles || canInvite) && (
|
||||
<MobileView
|
||||
t={t}
|
||||
titleProp={t("Upload")}
|
||||
actionOptions={actions}
|
||||
buttonOptions={uploadActions}
|
||||
isRooms={isRoomsFolder}
|
||||
mainButtonMobileVisible={mainButtonMobileVisible}
|
||||
onMainButtonClick={onCreateRoom}
|
||||
/>
|
||||
)}
|
||||
{!isArticleLoading &&
|
||||
!isProfile &&
|
||||
(security?.Create || canInvite) && (
|
||||
<MobileView
|
||||
t={t}
|
||||
titleProp={t("Upload")}
|
||||
actionOptions={actions}
|
||||
buttonOptions={uploadActions}
|
||||
isRooms={isRoomsFolder}
|
||||
mainButtonMobileVisible={mainButtonMobileVisible}
|
||||
onMainButtonClick={onCreateRoom}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : isRoomsFolder ? (
|
||||
<StyledButton
|
||||
@ -534,9 +553,11 @@ export default inject(
|
||||
|
||||
const { enablePlugins, currentColorScheme } = auth.settingsStore;
|
||||
|
||||
const security = selectedFolderStore.security;
|
||||
|
||||
const currentFolderId = selectedFolderStore.id;
|
||||
|
||||
const { isAdmin, isOwner, isVisitor } = auth.userStore.user;
|
||||
const { isAdmin, isOwner } = auth.userStore.user;
|
||||
|
||||
const { canCreateFiles } = accessRightsStore;
|
||||
|
||||
@ -572,9 +593,9 @@ export default inject(
|
||||
|
||||
isAdmin,
|
||||
isOwner,
|
||||
isVisitor,
|
||||
|
||||
mainButtonMobileVisible,
|
||||
security,
|
||||
};
|
||||
}
|
||||
)(
|
||||
|
@ -65,8 +65,10 @@ const RootFolderContainer = (props) => {
|
||||
isEmptyPage,
|
||||
setIsEmptyPage,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
sectionWidth,
|
||||
setIsLoadedEmptyPage,
|
||||
security,
|
||||
} = props;
|
||||
const personalDescription = t("EmptyFolderDecription");
|
||||
|
||||
@ -77,12 +79,14 @@ const RootFolderContainer = (props) => {
|
||||
const favoritesDescription = t("FavoritesEmptyContainerDescription");
|
||||
const recentDescription = t("RecentEmptyContainerDescription");
|
||||
|
||||
const roomsDescription = isVisitor
|
||||
? t("RoomEmptyContainerDescriptionUser")
|
||||
: t("RoomEmptyContainerDescription");
|
||||
const archiveRoomsDescription = isVisitor
|
||||
? t("ArchiveEmptyScreenUser")
|
||||
: t("ArchiveEmptyScreen");
|
||||
const roomsDescription =
|
||||
isVisitor || isCollaborator
|
||||
? t("RoomEmptyContainerDescriptionUser")
|
||||
: t("RoomEmptyContainerDescription");
|
||||
const archiveRoomsDescription =
|
||||
isVisitor || isCollaborator
|
||||
? t("ArchiveEmptyScreenUser")
|
||||
: t("ArchiveEmptyScreen");
|
||||
|
||||
const privateRoomHeader = t("PrivateRoomHeader");
|
||||
const privacyIcon = <img alt="" src={PrivacySvgUrl} />;
|
||||
@ -201,7 +205,7 @@ const RootFolderContainer = (props) => {
|
||||
imageSrc: theme.isBase
|
||||
? EmptyScreenCorporateSvgUrl
|
||||
: EmptyScreenCorporateDarkSvgUrl,
|
||||
buttons: isVisitor ? null : roomsButtons,
|
||||
buttons: !security?.Create ? null : roomsButtons,
|
||||
};
|
||||
case FolderType.Archive:
|
||||
return {
|
||||
@ -386,7 +390,7 @@ export default inject(
|
||||
setIsEmptyPage,
|
||||
setIsLoadedEmptyPage,
|
||||
} = filesStore;
|
||||
const { title, rootFolderType } = selectedFolderStore;
|
||||
const { title, rootFolderType, security } = selectedFolderStore;
|
||||
const { isPrivacyFolder, myFolderId } = treeFoldersStore;
|
||||
|
||||
return {
|
||||
@ -394,6 +398,7 @@ export default inject(
|
||||
isPrivacyFolder,
|
||||
isDesktop: isDesktopClient,
|
||||
isVisitor: auth.userStore.user.isVisitor,
|
||||
isCollaborator: auth.userStore.user.isCollaborator,
|
||||
isEncryptionSupport,
|
||||
organizationName,
|
||||
privacyInstructions,
|
||||
@ -411,6 +416,7 @@ export default inject(
|
||||
isEmptyPage,
|
||||
setIsEmptyPage,
|
||||
setIsLoadedEmptyPage,
|
||||
security,
|
||||
};
|
||||
}
|
||||
)(withTranslation(["Files"])(observer(RootFolderContainer)));
|
||||
|
@ -419,7 +419,7 @@ class TreeFolders extends React.Component {
|
||||
data: incomingDate,
|
||||
certainFolders,
|
||||
roomsFolderId,
|
||||
expandedPanelKeys,
|
||||
expandedPanelKeys = [],
|
||||
} = this.props;
|
||||
isExpand && this.setState({ isExpand: true });
|
||||
//console.log("load data...", treeNode);
|
||||
|
@ -15,6 +15,7 @@ const ChangeUserTypeEvent = ({
|
||||
peopleFilter,
|
||||
updateUserType,
|
||||
getUsersList,
|
||||
onClose,
|
||||
}) => {
|
||||
const {
|
||||
toType,
|
||||
@ -58,7 +59,7 @@ const ChangeUserTypeEvent = ({
|
||||
};
|
||||
|
||||
const onChangeUserType = () => {
|
||||
onClose();
|
||||
onClosePanel();
|
||||
updateUserType(toType, userIDs, peopleFilter, fromType)
|
||||
.then(() => {
|
||||
toastr.success(t("SuccessChangeUserType"));
|
||||
@ -83,14 +84,15 @@ const ChangeUserTypeEvent = ({
|
||||
});
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
const onClosePanel = () => {
|
||||
setVisible(false);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const onCloseAction = async () => {
|
||||
await getUsersList(peopleFilter);
|
||||
abortCallback && abortCallback();
|
||||
onClose();
|
||||
onClosePanel();
|
||||
};
|
||||
|
||||
const getType = (type) => {
|
||||
@ -99,6 +101,8 @@ const ChangeUserTypeEvent = ({
|
||||
return t("Common:DocSpaceAdmin");
|
||||
case "manager":
|
||||
return t("Common:RoomAdmin");
|
||||
case "collaborator":
|
||||
return t("Common:Collaborator");
|
||||
case "user":
|
||||
default:
|
||||
return t("Common:User");
|
||||
|
@ -48,7 +48,7 @@ const CreateEvent = ({
|
||||
|
||||
setEventDialogVisible,
|
||||
eventDialogVisible,
|
||||
createWithoutDialog,
|
||||
keepNewFileName,
|
||||
}) => {
|
||||
const [headerTitle, setHeaderTitle] = React.useState(null);
|
||||
const [startValue, setStartValue] = React.useState("");
|
||||
@ -77,7 +77,7 @@ const CreateEvent = ({
|
||||
|
||||
if (!extension) return setEventDialogVisible(true);
|
||||
|
||||
if (!createWithoutDialog) {
|
||||
if (!keepNewFileName) {
|
||||
setEventDialogVisible(true);
|
||||
} else {
|
||||
onSave(null, title || defaultName);
|
||||
@ -289,6 +289,7 @@ export default inject(
|
||||
uploadDataStore,
|
||||
dialogsStore,
|
||||
oformsStore,
|
||||
settingsStore,
|
||||
}) => {
|
||||
const {
|
||||
setIsLoading,
|
||||
@ -321,7 +322,7 @@ export default inject(
|
||||
eventDialogVisible,
|
||||
} = dialogsStore;
|
||||
|
||||
const { createWithoutDialog } = filesStore;
|
||||
const { keepNewFileName } = settingsStore;
|
||||
|
||||
return {
|
||||
setEventDialogVisible,
|
||||
@ -352,7 +353,7 @@ export default inject(
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
|
||||
createWithoutDialog,
|
||||
keepNewFileName,
|
||||
};
|
||||
}
|
||||
)(observer(CreateEvent));
|
||||
|
@ -22,9 +22,9 @@ const Dialog = ({
|
||||
onCancel,
|
||||
onClose,
|
||||
isCreateDialog,
|
||||
createWithoutDialog,
|
||||
setCreateWithoutDialog,
|
||||
extension,
|
||||
keepNewFileName,
|
||||
setKeepNewFileName,
|
||||
}) => {
|
||||
const [value, setValue] = useState("");
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
@ -32,8 +32,8 @@ const Dialog = ({
|
||||
const [isChanged, setIsChanged] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
createWithoutDialog && isCreateDialog && setIsChecked(createWithoutDialog);
|
||||
}, [isCreateDialog, createWithoutDialog]);
|
||||
keepNewFileName && isCreateDialog && setIsChecked(keepNewFileName);
|
||||
}, [isCreateDialog, keepNewFileName]);
|
||||
|
||||
useEffect(() => {
|
||||
let input = document?.getElementById("create-text-input");
|
||||
@ -80,7 +80,7 @@ const Dialog = ({
|
||||
const onSaveAction = useCallback(
|
||||
(e) => {
|
||||
setIsDisabled(true);
|
||||
isCreateDialog && setCreateWithoutDialog(isChecked);
|
||||
isCreateDialog && setKeepNewFileName(isChecked);
|
||||
onSave && onSave(e, value);
|
||||
},
|
||||
[onSave, isCreateDialog, value, isChecked]
|
||||
@ -88,7 +88,7 @@ const Dialog = ({
|
||||
|
||||
const onCancelAction = useCallback((e) => {
|
||||
if (isChecked) {
|
||||
setCreateWithoutDialog(false);
|
||||
setKeepNewFileName(false);
|
||||
}
|
||||
onCancel && onCancel(e);
|
||||
}, []);
|
||||
@ -96,7 +96,7 @@ const Dialog = ({
|
||||
const onCloseAction = useCallback(
|
||||
(e) => {
|
||||
if (!isDisabled && isChecked) {
|
||||
setCreateWithoutDialog(false);
|
||||
setKeepNewFileName(false);
|
||||
}
|
||||
onClose && onClose(e);
|
||||
},
|
||||
@ -171,9 +171,9 @@ const Dialog = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, filesStore }) => {
|
||||
export default inject(({ auth, settingsStore }) => {
|
||||
const { folderFormValidation } = auth.settingsStore;
|
||||
const { createWithoutDialog, setCreateWithoutDialog } = filesStore;
|
||||
const { keepNewFileName, setKeepNewFileName } = settingsStore;
|
||||
|
||||
return { folderFormValidation, createWithoutDialog, setCreateWithoutDialog };
|
||||
return { folderFormValidation, keepNewFileName, setKeepNewFileName };
|
||||
})(observer(Dialog));
|
||||
|
@ -39,6 +39,8 @@ const Bar = (props) => {
|
||||
|
||||
showRoomQuotaBar,
|
||||
showStorageQuotaBar,
|
||||
|
||||
currentColorScheme,
|
||||
} = props;
|
||||
|
||||
const [barVisible, setBarVisible] = useState({
|
||||
@ -112,13 +114,7 @@ const Bar = (props) => {
|
||||
}, []);
|
||||
|
||||
const sendActivationLinkAction = () => {
|
||||
if (sendActivationLink) {
|
||||
sendActivationLink(t).finally(() => {
|
||||
return onCloseActivationBar();
|
||||
});
|
||||
} else {
|
||||
onCloseActivationBar();
|
||||
}
|
||||
sendActivationLink && sendActivationLink(t);
|
||||
};
|
||||
|
||||
const onCloseActivationBar = () => {
|
||||
@ -183,6 +179,7 @@ const Bar = (props) => {
|
||||
|
||||
return (isRoomQuota || isStorageQuota) && tReady ? (
|
||||
<QuotasBar
|
||||
currentColorScheme={currentColorScheme}
|
||||
isRoomQuota={isRoomQuota}
|
||||
{...quotasValue}
|
||||
onClick={onClickQuota}
|
||||
@ -191,6 +188,7 @@ const Bar = (props) => {
|
||||
/>
|
||||
) : withActivationBar && barVisible.confirmEmail && tReady ? (
|
||||
<ConfirmEmailBar
|
||||
currentColorScheme={currentColorScheme}
|
||||
onLoad={onLoad}
|
||||
onClick={sendActivationLinkAction}
|
||||
onClose={onCloseActivationBar}
|
||||
@ -221,6 +219,8 @@ export default inject(({ auth, profileActionsStore }) => {
|
||||
showStorageQuotaBar,
|
||||
} = auth.currentQuotaStore;
|
||||
|
||||
const { currentColorScheme } = auth.settingsStore;
|
||||
|
||||
return {
|
||||
isAdmin: user?.isAdmin,
|
||||
withActivationBar,
|
||||
@ -236,5 +236,7 @@ export default inject(({ auth, profileActionsStore }) => {
|
||||
|
||||
showRoomQuotaBar,
|
||||
showStorageQuotaBar,
|
||||
|
||||
currentColorScheme,
|
||||
};
|
||||
})(withTranslation(["Profile", "Common"])(withRouter(observer(Bar))));
|
||||
|
@ -11,10 +11,17 @@ const StyledLink = styled(Link)`
|
||||
line-height: 16px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #316daa;
|
||||
color: ${(props) => props.currentColorScheme.main.accent};
|
||||
`;
|
||||
|
||||
const ConfirmEmailBar = ({ t, tReady, onClick, onClose, onLoad }) => {
|
||||
const ConfirmEmailBar = ({
|
||||
t,
|
||||
tReady,
|
||||
onClick,
|
||||
onClose,
|
||||
onLoad,
|
||||
currentColorScheme,
|
||||
}) => {
|
||||
return (
|
||||
tReady && (
|
||||
<SnackBar
|
||||
@ -22,7 +29,12 @@ const ConfirmEmailBar = ({ t, tReady, onClick, onClose, onLoad }) => {
|
||||
text={
|
||||
<>
|
||||
{t("ConfirmEmailDescription")}{" "}
|
||||
<StyledLink onClick={onClick}>{t("RequestActivation")}</StyledLink>
|
||||
<StyledLink
|
||||
currentColorScheme={currentColorScheme}
|
||||
onClick={onClick}
|
||||
>
|
||||
{t("RequestActivation")}
|
||||
</StyledLink>
|
||||
</>
|
||||
}
|
||||
isCampaigns={false}
|
||||
|
@ -11,7 +11,7 @@ const StyledLink = styled(Link)`
|
||||
line-height: 16px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #316daa;
|
||||
color: ${(props) => props.currentColorScheme.main.accent};
|
||||
`;
|
||||
|
||||
const QuotasBar = ({
|
||||
@ -23,6 +23,7 @@ const QuotasBar = ({
|
||||
onClick,
|
||||
onClose,
|
||||
onLoad,
|
||||
currentColorScheme,
|
||||
}) => {
|
||||
const onClickAction = () => {
|
||||
onClick && onClick(isRoomQuota);
|
||||
@ -37,7 +38,10 @@ const QuotasBar = ({
|
||||
description: (
|
||||
<Trans i18nKey="RoomQuotaDescription" t={t}>
|
||||
You can archived the unnecessary rooms or
|
||||
<StyledLink onClick={onClickAction}>
|
||||
<StyledLink
|
||||
currentColorScheme={currentColorScheme}
|
||||
onClick={onClickAction}
|
||||
>
|
||||
{{ clickHere: t("ClickHere") }}
|
||||
</StyledLink>{" "}
|
||||
to find a better pricing plan for your portal.
|
||||
@ -50,7 +54,10 @@ const QuotasBar = ({
|
||||
description: (
|
||||
<Trans i18nKey="StorageQuotaDescription" t={t}>
|
||||
You can remove the unnecessary files or{" "}
|
||||
<StyledLink onClick={onClickAction}>
|
||||
<StyledLink
|
||||
currentColorScheme={currentColorScheme}
|
||||
onClick={onClickAction}
|
||||
>
|
||||
{{ clickHere: t("ClickHere") }}
|
||||
</StyledLink>{" "}
|
||||
to find a better pricing plan for your portal.
|
||||
|
@ -85,7 +85,18 @@ const PeopleSelector = ({
|
||||
}, [isLoading]);
|
||||
|
||||
const toListItem = (item) => {
|
||||
const { id, email, avatar, icon, displayName, hasAvatar } = item;
|
||||
const {
|
||||
id,
|
||||
email,
|
||||
avatar,
|
||||
icon,
|
||||
displayName,
|
||||
hasAvatar,
|
||||
isOwner,
|
||||
isAdmin,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
} = item;
|
||||
|
||||
const role = getUserRole(item);
|
||||
|
||||
@ -98,6 +109,10 @@ const PeopleSelector = ({
|
||||
icon,
|
||||
label: displayName || email,
|
||||
role,
|
||||
isOwner,
|
||||
isAdmin,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -79,8 +79,6 @@ const AvatarEditorDialog = (props) => {
|
||||
const avatars = await createThumbnailsAvatar(profile.id, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 192,
|
||||
height: 192,
|
||||
tmpFile: res.data,
|
||||
});
|
||||
updateCreatedAvatar(avatars);
|
||||
|
@ -14,10 +14,11 @@ class ResetApplicationDialogComponent extends React.Component {
|
||||
}
|
||||
|
||||
resetApp = async () => {
|
||||
const { resetTfaApp, id, onClose, history } = this.props;
|
||||
const { t, resetTfaApp, id, onClose, history } = this.props;
|
||||
onClose && onClose();
|
||||
try {
|
||||
const res = await resetTfaApp(id);
|
||||
toastr.success(t("SuccessResetApplication"));
|
||||
if (res) history.push(res.replace(window.location.origin, ""));
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
|
@ -62,12 +62,19 @@ const AddUsersPanel = ({
|
||||
const currentItem = shareDataItems.find((x) => x.sharedTo.id === item.id);
|
||||
|
||||
if (!currentItem) {
|
||||
const currentAccess =
|
||||
item.isOwner || item.isAdmin
|
||||
? ShareAccessRights.RoomManager
|
||||
: access.access;
|
||||
|
||||
const newItem = {
|
||||
access: access.access,
|
||||
access: currentAccess,
|
||||
email: item.email,
|
||||
id: item.id,
|
||||
displayName: item.label,
|
||||
avatar: item.avatar,
|
||||
isOwner: item.isOwner,
|
||||
isAdmin: item.isAdmin,
|
||||
};
|
||||
items.push(newItem);
|
||||
}
|
||||
|
@ -35,12 +35,15 @@ const InvitePanel = ({
|
||||
userLink,
|
||||
guestLink,
|
||||
adminLink,
|
||||
collaboratorLink,
|
||||
defaultAccess,
|
||||
inviteUsers,
|
||||
setInfoPanelIsMobileHidden,
|
||||
reloadSelectionParentRoom,
|
||||
setUpdateRoomMembers,
|
||||
roomsView,
|
||||
getUsersList,
|
||||
filter,
|
||||
}) => {
|
||||
const [selectedRoom, setSelectedRoom] = useState(null);
|
||||
const [hasErrors, setHasErrors] = useState(false);
|
||||
@ -85,7 +88,8 @@ const InvitePanel = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (roomId === -1) {
|
||||
if (!userLink || !guestLink || !adminLink) getPortalInviteLinks();
|
||||
if (!userLink || !guestLink || !adminLink || !collaboratorLink)
|
||||
getPortalInviteLinks();
|
||||
|
||||
setShareLinks([
|
||||
{
|
||||
@ -106,6 +110,12 @@ const InvitePanel = ({
|
||||
shareLink: adminLink,
|
||||
access: 3,
|
||||
},
|
||||
{
|
||||
id: "collaborator",
|
||||
title: "Collaborator",
|
||||
shareLink: collaboratorLink,
|
||||
access: 4,
|
||||
},
|
||||
]);
|
||||
|
||||
return;
|
||||
@ -113,7 +123,7 @@ const InvitePanel = ({
|
||||
|
||||
selectRoom();
|
||||
getInfo();
|
||||
}, [roomId, userLink, guestLink, adminLink]);
|
||||
}, [roomId, userLink, guestLink, adminLink, collaboratorLink]);
|
||||
|
||||
useEffect(() => {
|
||||
const hasErrors = inviteItems.some((item) => !!item.errors?.length);
|
||||
@ -178,6 +188,10 @@ const InvitePanel = ({
|
||||
} catch (err) {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
} finally {
|
||||
if (roomId === -1) {
|
||||
await getUsersList(filter , false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -261,7 +275,8 @@ const InvitePanel = ({
|
||||
export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
|
||||
const { theme } = auth.settingsStore;
|
||||
|
||||
const { getUsersByQuery, inviteUsers } = peopleStore.usersStore;
|
||||
const { getUsersByQuery, inviteUsers, getUsersList } = peopleStore.usersStore;
|
||||
const { filter } = peopleStore.filterStore;
|
||||
const {
|
||||
setIsMobileHidden: setInfoPanelIsMobileHidden,
|
||||
reloadSelectionParentRoom,
|
||||
@ -275,6 +290,7 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
|
||||
userLink,
|
||||
guestLink,
|
||||
adminLink,
|
||||
collaboratorLink,
|
||||
} = peopleStore.inviteLinksStore;
|
||||
|
||||
const {
|
||||
@ -308,11 +324,14 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
|
||||
userLink,
|
||||
guestLink,
|
||||
adminLink,
|
||||
collaboratorLink,
|
||||
inviteUsers,
|
||||
setInfoPanelIsMobileHidden,
|
||||
reloadSelectionParentRoom,
|
||||
setUpdateRoomMembers,
|
||||
roomsView,
|
||||
getUsersList,
|
||||
filter,
|
||||
};
|
||||
})(
|
||||
withTranslation([
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
StyledDeleteIcon,
|
||||
StyledText,
|
||||
} from "../StyledInvitePanel";
|
||||
import { filterUserRoleOptions } from "SRC_DIR/helpers/utils";
|
||||
|
||||
const Item = ({
|
||||
t,
|
||||
@ -38,7 +39,11 @@ const Item = ({
|
||||
|
||||
const accesses = getAccessOptions(t, roomType, true, false, isOwner);
|
||||
|
||||
const defaultAccess = accesses.find((option) => option.access === +access);
|
||||
const filteredAccesses = filterUserRoleOptions(accesses, item, true);
|
||||
|
||||
const defaultAccess = filteredAccesses.find(
|
||||
(option) => option.access === +access
|
||||
);
|
||||
|
||||
const errorsInList = () => {
|
||||
const hasErrors = inviteItems.some((item) => !!item.errors?.length);
|
||||
@ -128,7 +133,7 @@ const Item = ({
|
||||
<StyledComboBox
|
||||
onSelect={selectItemAccess}
|
||||
noBorder
|
||||
options={accesses}
|
||||
options={filteredAccesses}
|
||||
size="content"
|
||||
scaled={false}
|
||||
manualWidth="fit-content"
|
||||
|
@ -31,6 +31,17 @@ export const getAccessOptions = (
|
||||
access:
|
||||
roomType === -1 ? EmployeeType.User : ShareAccessRights.RoomManager,
|
||||
},
|
||||
collaborator: {
|
||||
key: "collaborator",
|
||||
label: t("Common:Collaborator"),
|
||||
description: t("Translations:RoleCollaboratorDescription"),
|
||||
quota: t("Common:Paid"),
|
||||
color: "#EDC409",
|
||||
access:
|
||||
roomType === -1
|
||||
? EmployeeType.Collaborator
|
||||
: ShareAccessRights.Collaborator,
|
||||
},
|
||||
user: {
|
||||
key: "user",
|
||||
label: t("Common:User"),
|
||||
@ -73,6 +84,7 @@ export const getAccessOptions = (
|
||||
case RoomsType.FillingFormsRoom:
|
||||
options = [
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.formFiller,
|
||||
accesses.viewer,
|
||||
@ -81,6 +93,7 @@ export const getAccessOptions = (
|
||||
case RoomsType.EditingRoom:
|
||||
options = [
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.editor,
|
||||
accesses.viewer,
|
||||
@ -89,6 +102,7 @@ export const getAccessOptions = (
|
||||
case RoomsType.ReviewRoom:
|
||||
options = [
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.reviewer,
|
||||
accesses.commentator,
|
||||
@ -98,6 +112,7 @@ export const getAccessOptions = (
|
||||
case RoomsType.ReadOnlyRoom:
|
||||
options = [
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.viewer,
|
||||
];
|
||||
@ -105,6 +120,7 @@ export const getAccessOptions = (
|
||||
case RoomsType.CustomRoom:
|
||||
options = [
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.editor,
|
||||
accesses.formFiller,
|
||||
@ -119,6 +135,7 @@ export const getAccessOptions = (
|
||||
options = [
|
||||
...options,
|
||||
accesses.roomAdmin,
|
||||
accesses.collaborator,
|
||||
{ key: "s1", isSeparator: withSeparator },
|
||||
accesses.user,
|
||||
];
|
||||
|
@ -7,7 +7,6 @@ import toastr from "@docspace/components/toast/toastr";
|
||||
import SelectFolderDialog from "../SelectFolderDialog";
|
||||
import SimpleFileInput from "../../SimpleFileInput";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import SelectionPanel from "../SelectionPanel/SelectionPanelBody";
|
||||
import { FolderType } from "@docspace/common/constants";
|
||||
class SelectFolderInput extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@ -113,7 +112,7 @@ class SelectFolderInput extends React.PureComponent {
|
||||
onSelect && onSelect(folderId);
|
||||
};
|
||||
onSetFolderInfo = (folderId) => {
|
||||
const { setExpandedPanelKeys, setParentId } = this.props;
|
||||
const { setExpandedPanelKeys, setParentId, clearLocalStorage } = this.props;
|
||||
|
||||
getFolder(folderId)
|
||||
.then((data) => {
|
||||
@ -123,7 +122,10 @@ class SelectFolderInput extends React.PureComponent {
|
||||
setExpandedPanelKeys(pathParts);
|
||||
setParentId(data.current.parentId);
|
||||
})
|
||||
.catch((e) => toastr.error(e));
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
clearLocalStorage();
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -201,7 +203,9 @@ export default inject(
|
||||
treeFoldersStore,
|
||||
selectFolderDialogStore,
|
||||
selectedFolderStore,
|
||||
backup,
|
||||
}) => {
|
||||
const { clearLocalStorage } = backup;
|
||||
const { setFirstLoad } = filesStore;
|
||||
const { setExpandedPanelKeys } = treeFoldersStore;
|
||||
const {
|
||||
@ -220,6 +224,7 @@ export default inject(
|
||||
const { setParentId } = selectedFolderStore;
|
||||
|
||||
return {
|
||||
clearLocalStorage,
|
||||
setFirstLoad,
|
||||
setExpandedPanelKeys,
|
||||
setParentId,
|
||||
|
@ -12,9 +12,6 @@ import ActionsUploadedFile from "./SubComponents/ActionsUploadedFile";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import NoUserSelect from "@docspace/components/utils/commonStyles";
|
||||
import Button from "@docspace/components/button";
|
||||
import globalColors from "@docspace/components/utils/globalColors";
|
||||
|
||||
const buttonColor = globalColors.blueDisabled;
|
||||
|
||||
const StyledFileRow = styled(Row)`
|
||||
width: calc(100% - 16px);
|
||||
@ -145,11 +142,11 @@ class FileRow extends Component {
|
||||
onCancelCurrentUpload = (e) => {
|
||||
//console.log("cancel upload ", e);
|
||||
const { id, action, fileId } = e.currentTarget.dataset;
|
||||
const { cancelCurrentUpload, cancelCurrentFileConversion } = this.props;
|
||||
const { t, cancelCurrentUpload, cancelCurrentFileConversion } = this.props;
|
||||
|
||||
return action === "convert"
|
||||
? cancelCurrentFileConversion(fileId)
|
||||
: cancelCurrentUpload(id);
|
||||
: cancelCurrentUpload(id, t);
|
||||
};
|
||||
|
||||
onMediaClick = (id) => {
|
||||
@ -228,8 +225,6 @@ class FileRow extends Component {
|
||||
t,
|
||||
item,
|
||||
uploaded,
|
||||
//onMediaClick,
|
||||
currentFileUploadProgress,
|
||||
fileIcon,
|
||||
isMedia,
|
||||
ext,
|
||||
@ -314,7 +309,7 @@ class FileRow extends Component {
|
||||
data-id={item.uniqueId}
|
||||
onClick={this.onCancelCurrentUpload}
|
||||
>
|
||||
<LoadingButton percent={currentFileUploadProgress} />
|
||||
<LoadingButton item={item} />
|
||||
</div>
|
||||
)}
|
||||
{showPasswordInput && (
|
||||
@ -365,7 +360,6 @@ export default inject(
|
||||
const { canViewedDocs, getIconSrc, isArchive } = settingsStore;
|
||||
const {
|
||||
uploaded,
|
||||
primaryProgressDataStore,
|
||||
cancelCurrentUpload,
|
||||
cancelCurrentFileConversion,
|
||||
setUploadPanelVisible,
|
||||
@ -379,7 +373,6 @@ export default inject(
|
||||
setMediaViewerData,
|
||||
setCurrentItem,
|
||||
} = mediaViewerDataStore;
|
||||
const { loadingFile: file } = primaryProgressDataStore;
|
||||
|
||||
const isMedia =
|
||||
item.fileInfo?.viewAccessability?.ImageView ||
|
||||
@ -390,25 +383,16 @@ export default inject(
|
||||
|
||||
const fileIcon = getIconSrc(ext, 24);
|
||||
|
||||
const loadingFile = !file || !file.uniqueId ? null : file;
|
||||
|
||||
const currentFileUploadProgress =
|
||||
file && loadingFile.uniqueId === item.uniqueId
|
||||
? loadingFile.percent
|
||||
: null;
|
||||
|
||||
const downloadInCurrentTab = isArchive(ext) || !canViewedDocs(ext);
|
||||
|
||||
return {
|
||||
isPersonal: personal,
|
||||
theme,
|
||||
currentFileUploadProgress,
|
||||
uploaded,
|
||||
isMedia,
|
||||
isMedia: !!isMedia,
|
||||
fileIcon,
|
||||
ext,
|
||||
name,
|
||||
loadingFile,
|
||||
isMediaActive,
|
||||
downloadInCurrentTab,
|
||||
removeFileFromList,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import {
|
||||
StyledCircle,
|
||||
StyledCircleWrap,
|
||||
StyledLoadingButton,
|
||||
} from "@docspace/common/components/StyledLoadingButton";
|
||||
|
||||
@ -16,7 +16,6 @@ const LoadingButton = (props) => {
|
||||
onClick,
|
||||
isConversion,
|
||||
inConversion,
|
||||
...rest
|
||||
} = props;
|
||||
const [isAnimation, setIsAnimation] = useState(true);
|
||||
|
||||
@ -61,4 +60,22 @@ const LoadingButton = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingButton;
|
||||
export default inject(({ uploadDataStore }, { item }) => {
|
||||
const { primaryProgressDataStore, isParallel } = uploadDataStore;
|
||||
const { loadingFile: file } = primaryProgressDataStore;
|
||||
|
||||
const loadingFile = !file || !file.uniqueId ? null : file;
|
||||
|
||||
const currentFileUploadProgress =
|
||||
file && loadingFile?.uniqueId === item?.uniqueId
|
||||
? loadingFile.percent
|
||||
: null;
|
||||
|
||||
return {
|
||||
percent: isParallel
|
||||
? item?.percent
|
||||
? item.percent
|
||||
: null
|
||||
: currentFileUploadProgress,
|
||||
};
|
||||
})(observer(LoadingButton));
|
||||
|
@ -51,6 +51,8 @@ export const CategoryType = Object.freeze({
|
||||
Favorite: 5,
|
||||
Recent: 6,
|
||||
Trash: 7,
|
||||
Settings: 8,
|
||||
Accounts: 9,
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -40,8 +40,9 @@ export const getAccessIcon = (access) => {
|
||||
};
|
||||
|
||||
export const getTitleWithoutExst = (item, fromTemplate) => {
|
||||
return item.fileExst && !fromTemplate
|
||||
? item.title.split(".").slice(0, -1).join(".")
|
||||
const titleWithoutExst = item.title.split(".").slice(0, -1).join(".");
|
||||
return titleWithoutExst && item.fileExst && !fromTemplate
|
||||
? titleWithoutExst
|
||||
: item.title;
|
||||
};
|
||||
|
||||
|
@ -10,26 +10,3 @@ export const thumbnailStatuses = {
|
||||
};
|
||||
|
||||
export const ADS_TIMEOUT = 300000; // 5 min
|
||||
|
||||
export const FilterGroups = Object.freeze({
|
||||
filterType: "filter-filterType",
|
||||
filterAuthor: "filter-author",
|
||||
filterFolders: "filter-folders",
|
||||
filterContent: "filter-withContent",
|
||||
roomFilterProviderType: "filter-provider-type",
|
||||
roomFilterType: "filter-type",
|
||||
roomFilterSubject: "filter-subject",
|
||||
roomFilterOwner: "filter-owner",
|
||||
roomFilterTags: "filter-tags",
|
||||
roomFilterFolders: "filter-withSubfolders",
|
||||
roomFilterContent: "filter-content",
|
||||
});
|
||||
|
||||
export const FilterKeys = Object.freeze({
|
||||
withSubfolders: "withSubfolders",
|
||||
excludeSubfolders: "excludeSubfolders",
|
||||
withContent: "withContent",
|
||||
me: "me",
|
||||
other: "other",
|
||||
user: "user",
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import authStore from "@docspace/common/store/AuthStore";
|
||||
import { toCommunityHostname, getLanguage } from "@docspace/common/utils";
|
||||
import history from "@docspace/common/history";
|
||||
import { CategoryType } from "./constants";
|
||||
import { FolderType } from "@docspace/common/constants";
|
||||
import { FolderType, ShareAccessRights } from "@docspace/common/constants";
|
||||
import { translations } from "./autoGeneratedTranslations";
|
||||
|
||||
export const setDocumentTitle = (subTitle = null) => {
|
||||
@ -125,8 +125,12 @@ export const getCategoryType = (location) => {
|
||||
categoryType = CategoryType.Favorite;
|
||||
} else if (pathname.startsWith("/recent")) {
|
||||
categoryType = CategoryType.Recent;
|
||||
} else if (pathname.startsWith("/trash")) {
|
||||
} else if (pathname.startsWith("/files/trash")) {
|
||||
categoryType = CategoryType.Trash;
|
||||
} else if (pathname.startsWith("/settings")) {
|
||||
categoryType = CategoryType.Settings;
|
||||
} else if (pathname.startsWith("/accounts/filter")) {
|
||||
categoryType = CategoryType.Accounts;
|
||||
}
|
||||
|
||||
return categoryType;
|
||||
@ -186,3 +190,24 @@ export const getCategoryUrl = (categoryType, folderId = null) => {
|
||||
throw new Error("Unknown category type");
|
||||
}
|
||||
};
|
||||
|
||||
export const filterUserRoleOptions = (
|
||||
options,
|
||||
currentUser,
|
||||
withRemove = false
|
||||
) => {
|
||||
let newOptions = [...options];
|
||||
|
||||
if (currentUser?.isAdmin || currentUser?.isOwner) {
|
||||
newOptions = newOptions.filter(
|
||||
(o) =>
|
||||
+o.access === ShareAccessRights.RoomManager ||
|
||||
+o.access === ShareAccessRights.None ||
|
||||
(withRemove && (o.key === "s2" || o.key === "remove"))
|
||||
);
|
||||
|
||||
return newOptions;
|
||||
}
|
||||
|
||||
return newOptions;
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ const PeopleSection = React.memo(() => {
|
||||
<PrivateRoute exact path={["/accounts/view/@self"]} component={Profile} />
|
||||
<PrivateRoute
|
||||
exact
|
||||
withManager
|
||||
path={["/accounts"]}
|
||||
component={HomeRedirectToFilter}
|
||||
/>
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
SendInviteDialog,
|
||||
DeleteUsersDialog,
|
||||
ChangeNameDialog,
|
||||
ResetApplicationDialog,
|
||||
} from "SRC_DIR/components/dialogs";
|
||||
|
||||
const Dialogs = ({
|
||||
@ -28,10 +29,12 @@ const Dialogs = ({
|
||||
disableDialogVisible,
|
||||
sendInviteDialogVisible,
|
||||
deleteDialogVisible,
|
||||
resetAuthDialogVisible,
|
||||
|
||||
changeNameVisible,
|
||||
setChangeNameVisible,
|
||||
profile,
|
||||
resetTfaApp,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
@ -101,6 +104,15 @@ const Dialogs = ({
|
||||
fromList
|
||||
/>
|
||||
)}
|
||||
|
||||
{resetAuthDialogVisible && (
|
||||
<ResetApplicationDialog
|
||||
visible={resetAuthDialogVisible}
|
||||
onClose={closeDialogs}
|
||||
resetTfaApp={resetTfaApp}
|
||||
id={data}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -121,6 +133,7 @@ export default inject(({ auth, peopleStore }) => {
|
||||
disableDialogVisible,
|
||||
sendInviteDialogVisible,
|
||||
deleteDialogVisible,
|
||||
resetAuthDialogVisible,
|
||||
} = peopleStore.dialogStore;
|
||||
|
||||
const { user: profile } = auth.userStore;
|
||||
@ -130,6 +143,10 @@ export default inject(({ auth, peopleStore }) => {
|
||||
setChangeNameVisible,
|
||||
} = peopleStore.targetUserStore;
|
||||
|
||||
const { tfaStore } = auth;
|
||||
|
||||
const { unlinkApp: resetTfaApp } = tfaStore;
|
||||
|
||||
return {
|
||||
changeEmail,
|
||||
changePassword,
|
||||
@ -145,9 +162,12 @@ export default inject(({ auth, peopleStore }) => {
|
||||
disableDialogVisible,
|
||||
sendInviteDialogVisible,
|
||||
deleteDialogVisible,
|
||||
resetAuthDialogVisible,
|
||||
|
||||
changeNameVisible,
|
||||
setChangeNameVisible,
|
||||
profile,
|
||||
|
||||
resetTfaApp,
|
||||
};
|
||||
})(observer(Dialogs));
|
||||
|
@ -40,7 +40,14 @@ const UserContent = ({
|
||||
t,
|
||||
theme,
|
||||
}) => {
|
||||
const { displayName, email, statusType, role, isVisitor } = item;
|
||||
const {
|
||||
displayName,
|
||||
email,
|
||||
statusType,
|
||||
role,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
} = item;
|
||||
|
||||
const nameColor =
|
||||
statusType === "pending" || statusType === "disabled"
|
||||
@ -53,6 +60,8 @@ const UserContent = ({
|
||||
? t("Common:Owner")
|
||||
: role === "admin"
|
||||
? t("Common:DocSpaceAdmin")
|
||||
: isCollaborator
|
||||
? t("Common:Collaborator")
|
||||
: isVisitor
|
||||
? t("Common:User")
|
||||
: t("Common:RoomAdmin");
|
||||
|
@ -142,6 +142,7 @@ const PeopleTableRow = (props) => {
|
||||
|
||||
role,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
} = item;
|
||||
|
||||
const isPending = statusType === "pending" || statusType === "disabled";
|
||||
@ -168,6 +169,12 @@ const PeopleTableRow = (props) => {
|
||||
label: t("Common:RoomAdmin"),
|
||||
action: "manager",
|
||||
};
|
||||
const collaboratorOption = {
|
||||
key: "collaborator",
|
||||
title: t("Common:Collaborator"),
|
||||
label: t("Common:Collaborator"),
|
||||
action: "collaborator",
|
||||
};
|
||||
const userOption = {
|
||||
key: "user",
|
||||
title: t("Common:User"),
|
||||
@ -179,10 +186,12 @@ const PeopleTableRow = (props) => {
|
||||
|
||||
options.push(managerOption);
|
||||
|
||||
if (isCollaborator || isVisitor) options.push(collaboratorOption);
|
||||
|
||||
isVisitor && options.push(userOption);
|
||||
|
||||
return options;
|
||||
}, [t, isOwner, isVisitor]);
|
||||
}, [t, isOwner, isVisitor, isCollaborator]);
|
||||
|
||||
const onAbort = () => {
|
||||
setIsLoading(false);
|
||||
@ -227,6 +236,8 @@ const PeopleTableRow = (props) => {
|
||||
return t("Common:DocSpaceAdmin");
|
||||
case "manager":
|
||||
return t("Common:RoomAdmin");
|
||||
case "collaborator":
|
||||
return t("Common:Collaborator");
|
||||
case "user":
|
||||
return t("Common:User");
|
||||
}
|
||||
|
@ -11,7 +11,11 @@ import Loaders from "@docspace/common/components/Loaders";
|
||||
import { withLayoutSize } from "@docspace/common/utils";
|
||||
|
||||
import withPeopleLoader from "SRC_DIR/HOCs/withPeopleLoader";
|
||||
import { EmployeeType, PaymentsType } from "@docspace/common/constants";
|
||||
import {
|
||||
EmployeeType,
|
||||
EmployeeStatus,
|
||||
PaymentsType,
|
||||
} from "@docspace/common/constants";
|
||||
|
||||
const getStatus = (filterValues) => {
|
||||
const employeeStatus = result(
|
||||
@ -69,7 +73,6 @@ const SectionFilterContent = ({
|
||||
}) => {
|
||||
const [selectedFilterValues, setSelectedFilterValues] = React.useState(null);
|
||||
|
||||
//TODO: add new options from filter after update backend and fix manager from role
|
||||
const onFilter = (data) => {
|
||||
const status = getStatus(data);
|
||||
|
||||
@ -80,8 +83,12 @@ const SectionFilterContent = ({
|
||||
const newFilter = filter.clone();
|
||||
|
||||
if (status === 3) {
|
||||
newFilter.employeeStatus = 2;
|
||||
newFilter.employeeStatus = EmployeeStatus.Disabled;
|
||||
newFilter.activationStatus = null;
|
||||
} else if (status === 2) {
|
||||
console.log(status);
|
||||
newFilter.employeeStatus = EmployeeStatus.Active;
|
||||
newFilter.activationStatus = status;
|
||||
} else {
|
||||
newFilter.employeeStatus = null;
|
||||
newFilter.activationStatus = status;
|
||||
@ -94,6 +101,7 @@ const SectionFilterContent = ({
|
||||
newFilter.group = group;
|
||||
|
||||
newFilter.payments = payments;
|
||||
//console.log(newFilter);
|
||||
|
||||
setIsLoading(true);
|
||||
fetchPeople(newFilter, true).finally(() => setIsLoading(false));
|
||||
@ -123,7 +131,6 @@ const SectionFilterContent = ({
|
||||
fetchPeople(newFilter, true).finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
// TODO: change translation keys
|
||||
const getData = async () => {
|
||||
const statusItems = [
|
||||
{
|
||||
@ -172,6 +179,12 @@ const SectionFilterContent = ({
|
||||
group: "filter-type",
|
||||
label: t("Common:RoomAdmin"),
|
||||
},
|
||||
{
|
||||
id: "filter_type-room-admin",
|
||||
key: EmployeeType.Collaborator,
|
||||
group: "filter-type",
|
||||
label: t("Common:Collaborator"),
|
||||
},
|
||||
{
|
||||
id: "filter_type-user",
|
||||
key: EmployeeType.Guest,
|
||||
@ -312,6 +325,9 @@ const SectionFilterContent = ({
|
||||
case EmployeeType.User:
|
||||
label = t("Common:RoomAdmin");
|
||||
break;
|
||||
case EmployeeType.Collaborator:
|
||||
label = t("Common:Collaborator");
|
||||
break;
|
||||
case EmployeeType.Guest:
|
||||
label = t("Common:User");
|
||||
break;
|
||||
|
@ -72,6 +72,7 @@ const StyledContainer = styled.div`
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 33px;
|
||||
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
@ -42,11 +42,20 @@ const PureHome = ({
|
||||
|
||||
setSelectedNode,
|
||||
withPaging,
|
||||
onClickBack,
|
||||
}) => {
|
||||
const { location } = history;
|
||||
const { pathname } = location;
|
||||
//console.log("People Home render");
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("popstate", onClickBack);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("popstate", onClickBack);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (pathname.indexOf("/accounts/filter") > -1) {
|
||||
setSelectedNode(["accounts", "filter"]);
|
||||
@ -95,6 +104,7 @@ const PureHome = ({
|
||||
<Section.SectionBody>
|
||||
<SectionBodyContent />
|
||||
</Section.SectionBody>
|
||||
|
||||
<Section.InfoPanelHeader>
|
||||
<InfoPanelHeaderContent />
|
||||
</Section.InfoPanelHeader>
|
||||
@ -120,36 +130,45 @@ PureHome.propTypes = {
|
||||
|
||||
const Home = withTranslation("People")(PureHome);
|
||||
|
||||
export default inject(({ auth, peopleStore, treeFoldersStore }) => {
|
||||
const { settingsStore } = auth;
|
||||
const { showCatalog, withPaging } = settingsStore;
|
||||
const { usersStore, selectedGroupStore, loadingStore, viewAs } = peopleStore;
|
||||
const { getUsersList } = usersStore;
|
||||
const { selectedGroup } = selectedGroupStore;
|
||||
const { setSelectedNode } = treeFoldersStore;
|
||||
const {
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
setIsRefresh,
|
||||
firstLoad,
|
||||
setFirstLoad,
|
||||
} = loadingStore;
|
||||
export default inject(
|
||||
({ auth, peopleStore, treeFoldersStore, filesActionsStore }) => {
|
||||
const { settingsStore } = auth;
|
||||
const { showCatalog, withPaging } = settingsStore;
|
||||
const {
|
||||
usersStore,
|
||||
selectedGroupStore,
|
||||
loadingStore,
|
||||
viewAs,
|
||||
} = peopleStore;
|
||||
const { getUsersList } = usersStore;
|
||||
const { selectedGroup } = selectedGroupStore;
|
||||
const { setSelectedNode } = treeFoldersStore;
|
||||
const { onClickBack } = filesActionsStore;
|
||||
const {
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
setIsRefresh,
|
||||
firstLoad,
|
||||
setFirstLoad,
|
||||
} = loadingStore;
|
||||
|
||||
return {
|
||||
isAdmin: auth.isAdmin,
|
||||
isLoading,
|
||||
getUsersList,
|
||||
setIsLoading,
|
||||
setIsRefresh,
|
||||
selectedGroup,
|
||||
showCatalog,
|
||||
firstLoad,
|
||||
setFirstLoad,
|
||||
viewAs,
|
||||
setSelectedNode,
|
||||
checkedMaintenance: auth.settingsStore.checkedMaintenance,
|
||||
setMaintenanceExist: auth.settingsStore.setMaintenanceExist,
|
||||
snackbarExist: auth.settingsStore.snackbarExist,
|
||||
withPaging,
|
||||
};
|
||||
})(observer(withRouter(Home)));
|
||||
return {
|
||||
isAdmin: auth.isAdmin,
|
||||
isLoading,
|
||||
getUsersList,
|
||||
setIsLoading,
|
||||
setIsRefresh,
|
||||
selectedGroup,
|
||||
showCatalog,
|
||||
firstLoad,
|
||||
setFirstLoad,
|
||||
viewAs,
|
||||
setSelectedNode,
|
||||
checkedMaintenance: auth.settingsStore.checkedMaintenance,
|
||||
setMaintenanceExist: auth.settingsStore.setMaintenanceExist,
|
||||
snackbarExist: auth.settingsStore.snackbarExist,
|
||||
withPaging,
|
||||
onClickBack,
|
||||
};
|
||||
}
|
||||
)(observer(withRouter(Home)));
|
||||
|
@ -91,6 +91,7 @@ const FilesSection = React.memo(() => {
|
||||
<PrivateRoute
|
||||
restricted
|
||||
withManager
|
||||
withCollaborator
|
||||
path={[
|
||||
"/rooms/personal",
|
||||
"/rooms/personal/filter",
|
||||
@ -144,7 +145,6 @@ const FilesSection = React.memo(() => {
|
||||
<PrivateRoute
|
||||
exact
|
||||
restricted
|
||||
withManager
|
||||
path={"/settings/admin"}
|
||||
component={Settings}
|
||||
/>
|
||||
|
@ -100,9 +100,8 @@ class Tile extends React.PureComponent {
|
||||
};
|
||||
|
||||
onShowTemplateInfo = () => {
|
||||
if (!this.props.isInfoPanelVisible) {
|
||||
this.props.setIsInfoPanelVisible(true);
|
||||
}
|
||||
this.onSelectForm();
|
||||
if (!this.props.isInfoPanelVisible) this.props.setIsInfoPanelVisible(true);
|
||||
};
|
||||
|
||||
getOptions = () => ["create", "template-info"];
|
||||
|
@ -7,6 +7,7 @@ import getCorrectDate from "@docspace/components/utils/getCorrectDate";
|
||||
import Link from "@docspace/components/link";
|
||||
import Text from "@docspace/components/text";
|
||||
import Tag from "@docspace/components/tag";
|
||||
import { decode } from "he";
|
||||
|
||||
import {
|
||||
connectedCloudsTypeTitleTranslation as getProviderTranslation,
|
||||
@ -227,8 +228,8 @@ class DetailsHelper {
|
||||
const onOpenUser = () => this.openUser(this.item.createdBy, this.history);
|
||||
|
||||
return this.personal || this.isVisitor
|
||||
? text(decodeString(this.item.createdBy?.displayName))
|
||||
: link(decodeString(this.item.createdBy?.displayName), onOpenUser);
|
||||
? text(decode(this.item.createdBy?.displayName))
|
||||
: link(decode(this.item.createdBy?.displayName), onOpenUser);
|
||||
};
|
||||
|
||||
getItemLocation = () => {
|
||||
@ -279,8 +280,8 @@ class DetailsHelper {
|
||||
const onOpenUser = () => this.openUser(this.item.updatedBy, this.history);
|
||||
|
||||
return this.personal || this.isVisitor
|
||||
? text(decodeString(this.item.updatedBy?.displayName))
|
||||
: link(decodeString(this.item.updatedBy?.displayName), onOpenUser);
|
||||
? text(decode(this.item.updatedBy?.displayName))
|
||||
: link(decode(this.item.updatedBy?.displayName), onOpenUser);
|
||||
};
|
||||
|
||||
getItemCreationDate = () => {
|
||||
|
@ -21,6 +21,11 @@ class MembersHelper {
|
||||
label: this.t("Common:RoomAdmin"),
|
||||
access: ShareAccessRights.RoomManager,
|
||||
},
|
||||
collaborator: {
|
||||
key: "collaborator",
|
||||
label: this.t("Common:Collaborator"),
|
||||
access: ShareAccessRights.Collaborator,
|
||||
},
|
||||
viewer: {
|
||||
key: "viewer",
|
||||
label: this.t("Translations:RoleViewer"),
|
||||
@ -69,6 +74,7 @@ class MembersHelper {
|
||||
case RoomsType.FillingFormsRoom:
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.collaborator,
|
||||
options.formFiller,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
@ -76,6 +82,7 @@ class MembersHelper {
|
||||
case RoomsType.EditingRoom:
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.collaborator,
|
||||
options.editor,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
@ -83,16 +90,23 @@ class MembersHelper {
|
||||
case RoomsType.ReviewRoom:
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.collaborator,
|
||||
options.reviewer,
|
||||
options.commentator,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
case RoomsType.ReadOnlyRoom:
|
||||
return [options.roomAdmin, options.viewer, ...deleteOption];
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.collaborator,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
case RoomsType.CustomRoom:
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.collaborator,
|
||||
options.editor,
|
||||
options.formFiller,
|
||||
options.reviewer,
|
||||
|
@ -1,9 +1,10 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
import { hugeMobile, tablet } from "@docspace/components/utils/device";
|
||||
|
||||
const StyledAccountsItemTitle = styled.div`
|
||||
min-height: 104px;
|
||||
height: 104px;
|
||||
min-height: 80px;
|
||||
height: 80px;
|
||||
max-height: 104px;
|
||||
|
||||
display: flex;
|
||||
@ -11,8 +12,29 @@ const StyledAccountsItemTitle = styled.div`
|
||||
justify-content: start;
|
||||
gap: 16px;
|
||||
|
||||
position: fixed;
|
||||
margin-top: -80px;
|
||||
margin-left: -20px;
|
||||
width: calc(100% - 40px);
|
||||
padding: 24px 0 24px 20px;
|
||||
background: ${(props) => props.theme.infoPanel.backgroundColor};
|
||||
z-index: 100;
|
||||
|
||||
@media ${tablet} {
|
||||
width: 440px;
|
||||
padding: 24px 20px 24px 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 549px) {
|
||||
width: calc(100vw - 69px - 40px);
|
||||
}
|
||||
|
||||
@media ${hugeMobile} {
|
||||
width: calc(100vw - 32px);
|
||||
padding: 24px 0 24px 16px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
padding-top: 24px;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,9 @@ const StyledInfoPanelBody = styled.div`
|
||||
${({ isAccounts }) =>
|
||||
isAccounts
|
||||
? css`
|
||||
padding: 0px 3px 0 20px;
|
||||
padding: 80px 3px 0 20px;
|
||||
@media ${hugeMobile} {
|
||||
padding: 0px 8px 0 16px;
|
||||
padding: 80px 8px 0 16px;
|
||||
}
|
||||
`
|
||||
: css`
|
||||
|
@ -28,7 +28,6 @@ const StyledNoItemContainer = styled.div`
|
||||
}
|
||||
|
||||
.no-accounts {
|
||||
padding-top: 80px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -5,11 +5,11 @@ import { ReactSVG } from "react-svg";
|
||||
import { Text } from "@docspace/components";
|
||||
import { StyledTitle } from "../../styles/common";
|
||||
|
||||
const GalleryItemTitle = ({ selection, getIcon }) => {
|
||||
const GalleryItemTitle = ({ gallerySelected, getIcon }) => {
|
||||
return (
|
||||
<StyledTitle>
|
||||
<ReactSVG className="icon" src={getIcon(32, ".docxf")} />
|
||||
<Text className="text">{selection?.attributes?.name_form}</Text>
|
||||
<Text className="text">{gallerySelected?.attributes?.name_form}</Text>
|
||||
</StyledTitle>
|
||||
);
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ import GalleryItemTitle from "./GalleryItemTitle";
|
||||
|
||||
const ItemTitle = ({
|
||||
selection,
|
||||
gallerySelected,
|
||||
isRooms,
|
||||
isAccounts,
|
||||
isGallery,
|
||||
@ -30,7 +31,9 @@ const ItemTitle = ({
|
||||
);
|
||||
|
||||
if (isGallery)
|
||||
return <GalleryItemTitle selection={selection} getIcon={getIcon} />;
|
||||
return (
|
||||
<GalleryItemTitle gallerySelected={gallerySelected} getIcon={getIcon} />
|
||||
);
|
||||
|
||||
const filesItemSelection =
|
||||
isRooms &&
|
||||
@ -51,12 +54,14 @@ const ItemTitle = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, settingsStore, peopleStore }) => {
|
||||
export default inject(({ auth, settingsStore, peopleStore, oformsStore }) => {
|
||||
const { selectionParentRoom, roomsView } = auth.infoPanelStore;
|
||||
const { getIcon } = settingsStore;
|
||||
const { getUserContextOptions } = peopleStore.contextOptionsStore;
|
||||
const { gallerySelected } = oformsStore;
|
||||
|
||||
return {
|
||||
gallerySelected,
|
||||
getUserContextOptions,
|
||||
selectionParentRoom,
|
||||
roomsView,
|
||||
|
@ -22,7 +22,7 @@ const Accounts = ({
|
||||
const [statusLabel, setStatusLabel] = React.useState("");
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
const { role, id, isVisitor } = selection;
|
||||
const { role, id, isVisitor, isCollaborator } = selection;
|
||||
|
||||
React.useEffect(() => {
|
||||
getStatusLabel();
|
||||
@ -50,6 +50,8 @@ const Accounts = ({
|
||||
return t("Common:DocSpaceAdmin");
|
||||
case "manager":
|
||||
return t("Common:RoomAdmin");
|
||||
case "collaborator":
|
||||
return t("Common:Collaborator");
|
||||
case "user":
|
||||
return t("Common:User");
|
||||
}
|
||||
@ -72,6 +74,13 @@ const Accounts = ({
|
||||
label: t("Common:RoomAdmin"),
|
||||
action: "manager",
|
||||
};
|
||||
const collaboratorOption = {
|
||||
id: "info-account-type_collaborator",
|
||||
key: "collaborator",
|
||||
title: t("Common:Collaborator"),
|
||||
label: t("Common:Collaborator"),
|
||||
action: "collaborator",
|
||||
};
|
||||
const userOption = {
|
||||
id: "info-account-type_user",
|
||||
key: "user",
|
||||
@ -84,10 +93,12 @@ const Accounts = ({
|
||||
|
||||
options.push(managerOption);
|
||||
|
||||
if (isVisitor || isCollaborator) options.push(collaboratorOption);
|
||||
|
||||
isVisitor && options.push(userOption);
|
||||
|
||||
return options;
|
||||
}, [t, isAdmin, isOwner, isVisitor]);
|
||||
}, [t, isAdmin, isOwner, isVisitor, isCollaborator]);
|
||||
|
||||
const onAbort = () => {
|
||||
setIsLoading(false);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user