Merge branch 'master' into feature/thirdparty
This commit is contained in:
commit
c24bdfbbba
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@
|
||||
/products/ASC.People/Data/
|
||||
Data/
|
||||
Logs/
|
||||
**/.DS_Store
|
14
build/start/restart.bat
Normal file
14
build/start/restart.bat
Normal file
@ -0,0 +1,14 @@
|
||||
PUSHD %~dp0..
|
||||
call runasadmin.bat "%~dpnx0"
|
||||
|
||||
if %errorlevel% == 0 (
|
||||
for /R "run\" %%f in (*.bat) do (
|
||||
call nssm stop Onlyoffice%%~nf
|
||||
)
|
||||
|
||||
for /R "run\" %%f in (*.bat) do (
|
||||
call nssm start Onlyoffice%%~nf
|
||||
)
|
||||
|
||||
call iisreset
|
||||
)
|
@ -12,6 +12,7 @@ using ASC.Security.Cryptography;
|
||||
using ASC.Web.Studio.Core;
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -33,7 +34,8 @@ namespace ASC.Api.Core.Auth
|
||||
TenantManager tenantManager,
|
||||
UserManager userManager,
|
||||
AuthManager authManager,
|
||||
AuthContext authContext) :
|
||||
AuthContext authContext,
|
||||
IServiceProvider serviceProvider) :
|
||||
base(options, logger, encoder, clock)
|
||||
{
|
||||
SecurityContext = securityContext;
|
||||
@ -43,6 +45,7 @@ namespace ASC.Api.Core.Auth
|
||||
UserManager = userManager;
|
||||
AuthManager = authManager;
|
||||
AuthContext = authContext;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public SecurityContext SecurityContext { get; }
|
||||
@ -52,10 +55,12 @@ namespace ASC.Api.Core.Auth
|
||||
public UserManager UserManager { get; }
|
||||
public AuthManager AuthManager { get; }
|
||||
public AuthContext AuthContext { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
var emailValidationKeyModel = EmailValidationKeyModel.FromRequest(Context.Request);
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var emailValidationKeyModel = scope.ServiceProvider.GetService<EmailValidationKeyModel>();
|
||||
|
||||
if (!emailValidationKeyModel.Type.HasValue)
|
||||
{
|
||||
@ -67,7 +72,7 @@ namespace ASC.Api.Core.Auth
|
||||
EmailValidationKeyProvider.ValidationResult checkKeyResult;
|
||||
try
|
||||
{
|
||||
checkKeyResult = emailValidationKeyModel.Validate(EmailValidationKeyProvider, AuthContext, TenantManager, UserManager, AuthManager);
|
||||
checkKeyResult = emailValidationKeyModel.Validate();
|
||||
}
|
||||
catch (ArgumentNullException)
|
||||
{
|
||||
|
@ -49,13 +49,13 @@ namespace ASC.Core.Billing
|
||||
public DateTime DueDate { get; set; }
|
||||
|
||||
[JsonPropertyName("portal_count")]
|
||||
public int PortalCount { get; set; }
|
||||
|
||||
public int PortalCount { get; set; }
|
||||
|
||||
public bool Trial { get; set; }
|
||||
|
||||
[JsonPropertyName("user_quota")]
|
||||
public int ActiveUsers { get; set; }
|
||||
|
||||
[JsonPropertyName("user_quota")]
|
||||
public int ActiveUsers { get; set; }
|
||||
|
||||
[JsonPropertyName("customer_id")]
|
||||
public string CustomerId { get; set; }
|
||||
|
||||
@ -68,7 +68,16 @@ namespace ASC.Core.Billing
|
||||
|
||||
try
|
||||
{
|
||||
var license = JsonSerializer.Deserialize<License>(licenseString);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
options.Converters.Add(new LicenseConverter());
|
||||
|
||||
var license = JsonSerializer.Deserialize<License>(licenseString, options);
|
||||
|
||||
if (license == null) throw new BillingNotFoundException("Can't parse license");
|
||||
|
||||
license.OriginalLicense = licenseString;
|
||||
@ -80,5 +89,52 @@ namespace ASC.Core.Billing
|
||||
throw new BillingNotFoundException("Can't parse license");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LicenseConverter : JsonConverter<object>
|
||||
{
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
return
|
||||
typeof(int) == typeToConvert ||
|
||||
typeof(bool) == typeToConvert;
|
||||
}
|
||||
|
||||
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (typeToConvert == typeof(int) && reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
var i = reader.GetString();
|
||||
if (!int.TryParse(i, out var result))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (typeToConvert == typeof(bool))
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
var i = reader.GetString();
|
||||
if (!bool.TryParse(i, out var result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return reader.GetBoolean();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -27,15 +27,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -162,14 +159,8 @@ namespace ASC.Core.Billing
|
||||
licenseStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
const int bufferSize = 4096;
|
||||
using var fs = File.Open(path, FileMode.Create);
|
||||
var buffer = new byte[bufferSize];
|
||||
int readed;
|
||||
while ((readed = licenseStream.Read(buffer, 0, bufferSize)) != 0)
|
||||
{
|
||||
fs.Write(buffer, 0, readed);
|
||||
}
|
||||
using var fs = File.Open(path, FileMode.Create);
|
||||
licenseStream.CopyTo(fs);
|
||||
}
|
||||
|
||||
private DateTime Validate(License license)
|
||||
@ -281,52 +272,55 @@ namespace ASC.Core.Billing
|
||||
public DateTime VersionReleaseDate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_date != DateTime.MinValue) return _date;
|
||||
{
|
||||
// release sign is not longer requered
|
||||
return _date;
|
||||
|
||||
_date = DateTime.MaxValue;
|
||||
try
|
||||
{
|
||||
var versionDate = Configuration["version:release:date"];
|
||||
var sign = Configuration["version:release:sign"];
|
||||
//if (_date != DateTime.MinValue) return _date;
|
||||
|
||||
if (!sign.StartsWith("ASC "))
|
||||
{
|
||||
throw new Exception("sign without ASC");
|
||||
}
|
||||
//_date = DateTime.MaxValue;
|
||||
//try
|
||||
//{
|
||||
// var versionDate = Configuration["version:release:date"];
|
||||
// var sign = Configuration["version:release:sign"];
|
||||
|
||||
var splitted = sign.Substring(4).Split(':');
|
||||
var pkey = splitted[0];
|
||||
if (pkey != versionDate)
|
||||
{
|
||||
throw new Exception("sign with different date");
|
||||
}
|
||||
// if (!sign.StartsWith("ASC "))
|
||||
// {
|
||||
// throw new Exception("sign without ASC");
|
||||
// }
|
||||
|
||||
var date = splitted[1];
|
||||
var orighash = splitted[2];
|
||||
// var splitted = sign.Substring(4).Split(':');
|
||||
// var pkey = splitted[0];
|
||||
// if (pkey != versionDate)
|
||||
// {
|
||||
// throw new Exception("sign with different date");
|
||||
// }
|
||||
|
||||
var skey = Configuration["core:machinekey"];
|
||||
// var date = splitted[1];
|
||||
// var orighash = splitted[2];
|
||||
|
||||
using (var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(skey)))
|
||||
{
|
||||
var data = string.Join("\n", date, pkey);
|
||||
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
|
||||
{
|
||||
throw new Exception("incorrect hash");
|
||||
}
|
||||
}
|
||||
// var skey = Configuration["core:machinekey"];
|
||||
|
||||
var year = int.Parse(versionDate.Substring(0, 4));
|
||||
var month = int.Parse(versionDate.Substring(4, 2));
|
||||
var day = int.Parse(versionDate.Substring(6, 2));
|
||||
_date = new DateTime(year, month, day);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("VersionReleaseDate", ex);
|
||||
}
|
||||
return _date;
|
||||
// using (var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(skey)))
|
||||
// {
|
||||
// var data = string.Join("\n", date, pkey);
|
||||
// var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
// if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
|
||||
// {
|
||||
// throw new Exception("incorrect hash");
|
||||
// }
|
||||
// }
|
||||
|
||||
// var year = int.Parse(versionDate.Substring(0, 4));
|
||||
// var month = int.Parse(versionDate.Substring(4, 2));
|
||||
// var day = int.Parse(versionDate.Substring(6, 2));
|
||||
// _date = new DateTime(year, month, day);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Log.Error("VersionReleaseDate", ex);
|
||||
//}
|
||||
//return _date;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,7 +487,8 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
Tenant = tenant,
|
||||
Tariff = bi.Item1,
|
||||
Stamp = bi.Item2
|
||||
Stamp = bi.Item2,
|
||||
CreateOn = DateTime.UtcNow
|
||||
};
|
||||
|
||||
CoreDbContext.Tariffs.Add(efTariff);
|
||||
|
@ -91,7 +91,7 @@ namespace ASC.Core.Data
|
||||
PaymentId = r.PaymentId,
|
||||
Spam = r.Spam,
|
||||
Status = r.Status,
|
||||
StatusChangeDate = r.StatusChanged,
|
||||
StatusChangeDate = r.StatusChangedHack ?? DateTime.MinValue,
|
||||
TenantAlias = r.Alias,
|
||||
TenantId = r.Id,
|
||||
MappedDomain = r.MappedDomain,
|
||||
@ -382,9 +382,10 @@ namespace ASC.Core.Data
|
||||
{
|
||||
Id = key,
|
||||
Tenant = tenant,
|
||||
Value = data
|
||||
Value = data,
|
||||
LastModified = DateTime.UtcNow
|
||||
};
|
||||
TenantDbContext.CoreSettings.Add(settings);
|
||||
TenantDbContext.AddOrUpdate(r => r.CoreSettings, settings);
|
||||
}
|
||||
TenantDbContext.SaveChanges();
|
||||
tx.Commit();
|
||||
|
@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
namespace ASC.Core.Common.EF.Model
|
||||
{
|
||||
[Table("core_settings")]
|
||||
public class DbCoreSettings
|
||||
public class DbCoreSettings : BaseEntity
|
||||
{
|
||||
public int Tenant { get; set; }
|
||||
public string Id { get; set; }
|
||||
@ -13,6 +13,11 @@ namespace ASC.Core.Common.EF.Model
|
||||
|
||||
[Column("last_modified")]
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { Tenant, Id };
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoreSettingsExtension
|
||||
|
@ -15,15 +15,23 @@ namespace ASC.Core.Common.EF.Model
|
||||
public string Alias { get; set; }
|
||||
public string MappedDomain { get; set; }
|
||||
public int Version { get; set; }
|
||||
public DateTime? Version_Changed { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateTime VersionChanged { get => Version_Changed ?? DateTime.MinValue; set => Version_Changed = value; }
|
||||
|
||||
[Column("version_changed")]
|
||||
public DateTime VersionChanged { get; set; }
|
||||
public string Language { get; set; }
|
||||
public string TimeZone { get; set; }
|
||||
public string TrustedDomains { get; set; }
|
||||
public TenantTrustedDomainsType TrustedDomainsEnabled { get; set; }
|
||||
public TenantStatus Status { get; set; }
|
||||
public DateTime StatusChanged { get; set; }
|
||||
|
||||
public DateTime? StatusChanged { get; set; }
|
||||
|
||||
//hack for DateTime?
|
||||
[NotMapped]
|
||||
public DateTime? StatusChangedHack { get { return StatusChanged; } set { StatusChanged = value; } }
|
||||
|
||||
public DateTime CreationDateTime { get; set; }
|
||||
|
||||
[Column("owner_id")]
|
||||
|
@ -156,64 +156,30 @@ namespace ASC.Security.Cryptography
|
||||
public string Email { get; set; }
|
||||
public Guid? UiD { get; set; }
|
||||
public ConfirmType? Type { get; set; }
|
||||
public int? P { get; set; }
|
||||
public int? P { get; set; }
|
||||
public EmailValidationKeyProvider Provider { get; }
|
||||
public AuthContext AuthContext { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public UserManager UserManager { get; }
|
||||
public AuthManager Authentication { get; }
|
||||
|
||||
public EmailValidationKeyModel(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
EmailValidationKeyProvider provider,
|
||||
AuthContext authContext,
|
||||
TenantManager tenantManager,
|
||||
UserManager userManager,
|
||||
AuthManager authentication)
|
||||
{
|
||||
Provider = provider;
|
||||
AuthContext = authContext;
|
||||
TenantManager = tenantManager;
|
||||
UserManager = userManager;
|
||||
Authentication = authentication;
|
||||
|
||||
var request = QueryHelpers.ParseQuery(httpContextAccessor.HttpContext.Request.Headers["confirm"]);
|
||||
|
||||
public ValidationResult Validate(EmailValidationKeyProvider provider, AuthContext authContext, TenantManager tenantManager, UserManager userManager, AuthManager authentication)
|
||||
{
|
||||
ValidationResult checkKeyResult;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ConfirmType.EmpInvite:
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + (int)EmplType, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.LinkInvite:
|
||||
checkKeyResult = provider.ValidateEmailKey(Type.ToString() + (int)EmplType, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.PortalOwnerChange:
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + UiD.HasValue, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.EmailChange:
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + authContext.CurrentAccount.ID, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.PasswordChange:
|
||||
var hash = string.Empty;
|
||||
|
||||
if (P == 1)
|
||||
{
|
||||
var tenantId = tenantManager.GetCurrentTenant().TenantId;
|
||||
hash = authentication.GetUserPasswordHash(tenantId, UiD.Value);
|
||||
}
|
||||
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + (string.IsNullOrEmpty(hash) ? string.Empty : Hasher.Base64Hash(hash)) + UiD, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.Activation:
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + UiD, Key, provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.ProfileRemove:
|
||||
// validate UiD
|
||||
if (P == 1)
|
||||
{
|
||||
var user = userManager.GetUsers(UiD.GetValueOrDefault());
|
||||
if (user == null || user.Status == EmployeeStatus.Terminated || authContext.IsAuthenticated && authContext.CurrentAccount.ID != UiD)
|
||||
return ValidationResult.Invalid;
|
||||
}
|
||||
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type + UiD, Key, provider.ValidInterval);
|
||||
break;
|
||||
default:
|
||||
checkKeyResult = provider.ValidateEmailKey(Email + Type, Key, provider.ValidInterval);
|
||||
break;
|
||||
}
|
||||
|
||||
return checkKeyResult;
|
||||
}
|
||||
|
||||
public static EmailValidationKeyModel FromRequest(HttpRequest httpRequest)
|
||||
{
|
||||
var Request = QueryHelpers.ParseQuery(httpRequest.Headers["confirm"]);
|
||||
|
||||
_ = Request.TryGetValue("type", out var type);
|
||||
_ = request.TryGetValue("type", out var type);
|
||||
|
||||
ConfirmType? cType = null;
|
||||
if (Enum.TryParse<ConfirmType>(type, out var confirmType))
|
||||
@ -221,27 +187,78 @@ namespace ASC.Security.Cryptography
|
||||
cType = confirmType;
|
||||
}
|
||||
|
||||
_ = Request.TryGetValue("key", out var key);
|
||||
_ = request.TryGetValue("key", out var key);
|
||||
|
||||
_ = Request.TryGetValue("p", out var pkey);
|
||||
_ = request.TryGetValue("p", out var pkey);
|
||||
_ = int.TryParse(pkey, out var p);
|
||||
|
||||
_ = Request.TryGetValue("emplType", out var emplType);
|
||||
_ = request.TryGetValue("emplType", out var emplType);
|
||||
_ = Enum.TryParse<EmployeeType>(emplType, out var employeeType);
|
||||
|
||||
_ = Request.TryGetValue("email", out var _email);
|
||||
_ = Request.TryGetValue("uid", out var userIdKey);
|
||||
_ = request.TryGetValue("email", out var _email);
|
||||
_ = request.TryGetValue("uid", out var userIdKey);
|
||||
_ = Guid.TryParse(userIdKey, out var userId);
|
||||
|
||||
return new EmailValidationKeyModel
|
||||
Key = key;
|
||||
Type = cType;
|
||||
Email = _email;
|
||||
EmplType = employeeType;
|
||||
UiD = userId;
|
||||
P = p;
|
||||
}
|
||||
|
||||
public ValidationResult Validate()
|
||||
{
|
||||
ValidationResult checkKeyResult;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
Key = key,
|
||||
Type = cType,
|
||||
Email = _email,
|
||||
EmplType = employeeType,
|
||||
UiD = userId,
|
||||
P = p
|
||||
};
|
||||
case ConfirmType.EmpInvite:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + (int)EmplType, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.LinkInvite:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Type.ToString() + (int)EmplType, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.PortalOwnerChange:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + UiD.HasValue, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.EmailChange:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + AuthContext.CurrentAccount.ID, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.PasswordChange:
|
||||
var hash = string.Empty;
|
||||
|
||||
if (P == 1)
|
||||
{
|
||||
var tenantId = TenantManager.GetCurrentTenant().TenantId;
|
||||
hash = Authentication.GetUserPasswordHash(tenantId, UiD.Value);
|
||||
}
|
||||
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + (string.IsNullOrEmpty(hash) ? string.Empty : Hasher.Base64Hash(hash)) + UiD, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.Activation:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + UiD, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.ProfileRemove:
|
||||
// validate UiD
|
||||
if (P == 1)
|
||||
{
|
||||
var user = UserManager.GetUsers(UiD.GetValueOrDefault());
|
||||
if (user == null || user.Status == EmployeeStatus.Terminated || AuthContext.IsAuthenticated && AuthContext.CurrentAccount.ID != UiD)
|
||||
return ValidationResult.Invalid;
|
||||
}
|
||||
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + UiD, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.Wizard:
|
||||
checkKeyResult = Provider.ValidateEmailKey("" + Type, Key, Provider.ValidInterval);
|
||||
break;
|
||||
default:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type, Key, Provider.ValidInterval);
|
||||
break;
|
||||
}
|
||||
|
||||
return checkKeyResult;
|
||||
}
|
||||
|
||||
public void Deconstruct(out string key, out string email, out EmployeeType? employeeType, out Guid? userId, out ConfirmType? confirmType, out int? p)
|
||||
@ -252,13 +269,11 @@ namespace ASC.Security.Cryptography
|
||||
{
|
||||
public static DIHelper AddEmailValidationKeyProviderService(this DIHelper services)
|
||||
{
|
||||
if (services.TryAddScoped<EmailValidationKeyProvider>())
|
||||
{
|
||||
return services
|
||||
.AddTenantManagerService();
|
||||
}
|
||||
|
||||
return services;
|
||||
services.TryAddTransient<EmailValidationKeyModel>();
|
||||
services.TryAddScoped<EmailValidationKeyProvider>();
|
||||
|
||||
return services
|
||||
.AddTenantManagerService();
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ namespace ASC.Web.Studio.Utility
|
||||
PhoneAuth,
|
||||
Auth,
|
||||
TfaActivation,
|
||||
TfaAuth
|
||||
TfaAuth,
|
||||
Wizard
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ namespace ASC.Resource.Manager
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
var diHelper = new DIHelper(services);
|
||||
services.AddLogging();
|
||||
diHelper.TryAddScoped<ResourceData>();
|
||||
|
||||
diHelper.AddDbContextManagerService<ResourceDbContext>();
|
||||
diHelper.AddLoggerService();
|
||||
diHelper.AddNLogManager();
|
||||
diHelper.TryAddSingleton(Configuration);
|
||||
}
|
||||
diHelper.TryAddSingleton(Configuration); }
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,9 @@
|
||||
"url-shortener": {
|
||||
"value" : "/sh/",
|
||||
"internal": "http://localhost:9999/"
|
||||
},
|
||||
"controlpanel": {
|
||||
"url": ""
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
@ -116,5 +119,5 @@
|
||||
},
|
||||
"bookmarking": {
|
||||
"thumbnail-url": "http://localhost:9800/?url={0}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"kafka": {
|
||||
"kafka": {
|
||||
"BootstrapServers": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ namespace ASC.Files.Core.Data
|
||||
if (file.CreateOn == default) file.CreateOn = TenantUtil.DateTimeNow();
|
||||
|
||||
toUpdate = FilesDbContext.Files
|
||||
.Where(r => r.Id == file.ID && r.Version == file.Version)
|
||||
.Where(r => r.Id == file.ID && r.Version == file.Version && r.TenantId == TenantID)
|
||||
.FirstOrDefault();
|
||||
|
||||
toUpdate.Version = file.Version;
|
||||
@ -880,7 +880,7 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
var toUpdate = Query(FilesDbContext.Files)
|
||||
.Where(r => r.Id == fileId)
|
||||
.Where(r => r.Version >= fileVersion);
|
||||
.Where(r => r.Version > fileVersion);
|
||||
|
||||
foreach (var f in toUpdate)
|
||||
{
|
||||
@ -903,8 +903,8 @@ namespace ASC.Files.Core.Data
|
||||
|
||||
var toUpdate = Query(FilesDbContext.Files)
|
||||
.Where(r => r.Id == fileId)
|
||||
.Where(r => r.Version >= fileVersion)
|
||||
.Where(r => r.VersionGroup >= versionGroup);
|
||||
.Where(r => r.Version > fileVersion)
|
||||
.Where(r => r.VersionGroup > versionGroup);
|
||||
|
||||
foreach (var f in toUpdate)
|
||||
{
|
||||
|
@ -85,11 +85,11 @@ namespace ASC.Api.Documents
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public Guid Id;
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string ShareLink;
|
||||
public string ShareLink { get; set; }
|
||||
}
|
||||
public class FileShareWrapperHelper
|
||||
{
|
||||
|
@ -95,7 +95,15 @@ namespace ASC.Api.Documents
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public bool? Encrypted { get; set; }
|
||||
public bool? Encrypted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public bool? Locked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string LockedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
@ -187,7 +195,10 @@ namespace ASC.Api.Documents
|
||||
result.FileStatus = file.FileStatus;
|
||||
result.PureContentLength = file.ContentLength.NullIfDefault();
|
||||
result.Comment = file.Comment;
|
||||
result.Encrypted = file.Encrypted.NullIfDefault();
|
||||
result.Encrypted = file.Encrypted.NullIfDefault();
|
||||
result.Locked = file.Locked.NullIfDefault();
|
||||
result.LockedBy = file.LockedBy;
|
||||
|
||||
try
|
||||
{
|
||||
result.ViewUrl = CommonLinkUtility.GetFullAbsolutePath(file.DownloadUrl);
|
||||
|
7
products/ASC.Files/Core/Model/LockFileModel.cs
Normal file
7
products/ASC.Files/Core/Model/LockFileModel.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace ASC.Files.Core.Model
|
||||
{
|
||||
public class LockFileModel
|
||||
{
|
||||
public bool LockFile { get; set; }
|
||||
}
|
||||
}
|
@ -1073,6 +1073,18 @@ namespace ASC.Api.Documents
|
||||
return FilesControllerHelperInt.ChangeHistory(fileId, model.Version, model.ContinueVersion);
|
||||
}
|
||||
|
||||
[Update("file/{fileId}/lock", DisableFormat = true)]
|
||||
public FileWrapper<string> LockFile(string fileId, LockFileModel model)
|
||||
{
|
||||
return FilesControllerHelperString.LockFile(fileId, model.LockFile);
|
||||
}
|
||||
|
||||
[Update("file/{fileId:int}/lock")]
|
||||
public FileWrapper<int> LockFile(int fileId, LockFileModel model)
|
||||
{
|
||||
return FilesControllerHelperInt.LockFile(fileId, model.LockFile);
|
||||
}
|
||||
|
||||
[Update("file/{fileId}/comment", DisableFormat = true)]
|
||||
public object UpdateComment(string fileId, UpdateCommentModel model)
|
||||
{
|
||||
|
@ -549,6 +549,12 @@ namespace ASC.Files.Helpers
|
||||
return history.Select(FileWrapperHelper.Get);
|
||||
}
|
||||
|
||||
public FileWrapper<T> LockFile(T fileId, bool lockFile)
|
||||
{
|
||||
var result = FileStorageService.LockFile(fileId, lockFile);
|
||||
return FileWrapperHelper.Get(result);
|
||||
}
|
||||
|
||||
public string UpdateComment(T fileId, int version, string comment)
|
||||
{
|
||||
return FileStorageService.UpdateComment(fileId, version, comment);
|
||||
|
@ -36,4 +36,8 @@
|
||||
<ProjectReference Include="..\ASC.Web.Core\ASC.Web.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -51,7 +51,7 @@ namespace ASC.Web.Api.Controllers
|
||||
}
|
||||
|
||||
[Create(false)]
|
||||
public AuthenticationTokenData AuthenticateMe([FromBody]AuthModel auth)
|
||||
public AuthenticationTokenData AuthenticateMe([FromBody] AuthModel auth)
|
||||
{
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
var user = GetUser(tenant.TenantId, auth.UserName, auth.Password);
|
||||
@ -83,9 +83,9 @@ namespace ASC.Web.Api.Controllers
|
||||
|
||||
[AllowAnonymous]
|
||||
[Create("confirm", false)]
|
||||
public ValidationResult CheckConfirm([FromBody]EmailValidationKeyModel model)
|
||||
public ValidationResult CheckConfirm([FromBody] EmailValidationKeyModel model)
|
||||
{
|
||||
return model.Validate(EmailValidationKeyProvider, AuthContext, TenantManager, UserManager, AuthManager);
|
||||
return model.Validate();
|
||||
}
|
||||
|
||||
private UserInfo GetUser(int tenantId, string userName, string password)
|
||||
|
@ -31,6 +31,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Security;
|
||||
using System.ServiceModel.Security;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
@ -75,6 +76,7 @@ using ASC.Web.Studio.Core.SMS;
|
||||
using ASC.Web.Studio.Core.Statistic;
|
||||
using ASC.Web.Studio.Core.TFA;
|
||||
using ASC.Web.Studio.UserControls.CustomNavigation;
|
||||
using ASC.Web.Studio.UserControls.FirstTime;
|
||||
using ASC.Web.Studio.UserControls.Statistics;
|
||||
using ASC.Web.Studio.Utility;
|
||||
|
||||
@ -112,6 +114,7 @@ namespace ASC.Api.Settings
|
||||
public ProviderManager ProviderManager { get; }
|
||||
public MobileDetector MobileDetector { get; }
|
||||
public IOptionsSnapshot<AccountLinker> AccountLinker { get; }
|
||||
public FirstTimeTenantSettings FirstTimeTenantSettings { get; }
|
||||
public UserManager UserManager { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public TenantExtra TenantExtra { get; }
|
||||
@ -196,7 +199,8 @@ namespace ASC.Api.Settings
|
||||
IMemoryCache memoryCache,
|
||||
ProviderManager providerManager,
|
||||
MobileDetector mobileDetector,
|
||||
IOptionsSnapshot<AccountLinker> accountLinker)
|
||||
IOptionsSnapshot<AccountLinker> accountLinker,
|
||||
FirstTimeTenantSettings firstTimeTenantSettings)
|
||||
{
|
||||
Log = option.Get("ASC.Api");
|
||||
WebHostEnvironment = webHostEnvironment;
|
||||
@ -211,6 +215,7 @@ namespace ASC.Api.Settings
|
||||
ProviderManager = providerManager;
|
||||
MobileDetector = mobileDetector;
|
||||
AccountLinker = accountLinker;
|
||||
FirstTimeTenantSettings = firstTimeTenantSettings;
|
||||
MessageService = messageService;
|
||||
StudioNotifyService = studioNotifyService;
|
||||
ApiContext = apiContext;
|
||||
@ -249,7 +254,7 @@ namespace ASC.Api.Settings
|
||||
StorageSettingsHelper = storageSettingsHelper;
|
||||
}
|
||||
|
||||
[Read("")]
|
||||
[Read("", Check = false)]
|
||||
[AllowAnonymous]
|
||||
public SettingsWrapper GetSettings()
|
||||
{
|
||||
@ -272,6 +277,11 @@ namespace ASC.Api.Settings
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SettingsManager.Load<WizardSettings>().Completed)
|
||||
{
|
||||
settings.WizardToken = CommonLinkUtility.GetToken("", ConfirmType.Wizard, userId: Tenant.OwnerId);
|
||||
}
|
||||
|
||||
settings.EnabledJoin =
|
||||
(Tenant.TrustedDomainsType == TenantTrustedDomainsType.Custom &&
|
||||
Tenant.TrustedDomains.Count > 0) ||
|
||||
@ -525,15 +535,17 @@ namespace ASC.Api.Settings
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[Read("cultures")]
|
||||
[Read("cultures", Check = false)]
|
||||
public IEnumerable<object> GetSupportedCultures()
|
||||
{
|
||||
return SetupInfo.EnabledCultures.Select(r => r.Name).ToArray();
|
||||
}
|
||||
|
||||
[Read("timezones")]
|
||||
public List<object> GetTimeZones()
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard,Administrators")]
|
||||
[Read("timezones", Check = false)]
|
||||
public List<TimezonesModel> GetTimeZones()
|
||||
{
|
||||
ApiContext.AuthByClaim();
|
||||
var timeZones = TimeZoneInfo.GetSystemTimeZones().ToList();
|
||||
|
||||
if (timeZones.All(tz => tz.Id != "UTC"))
|
||||
@ -541,7 +553,7 @@ namespace ASC.Api.Settings
|
||||
timeZones.Add(TimeZoneInfo.Utc);
|
||||
}
|
||||
|
||||
var listOfTimezones = new List<object>();
|
||||
var listOfTimezones = new List<TimezonesModel>();
|
||||
|
||||
foreach (var tz in timeZones.OrderBy(z => z.BaseUtcOffset))
|
||||
{
|
||||
@ -565,6 +577,13 @@ namespace ASC.Api.Settings
|
||||
return listOfTimezones;
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard")]
|
||||
[Read("machine", Check = false)]
|
||||
public string GetMachineName()
|
||||
{
|
||||
return Dns.GetHostName().ToLowerInvariant();
|
||||
}
|
||||
|
||||
/* [Read("greetingsettings")]
|
||||
public string GetGreetingSettings()
|
||||
{
|
||||
@ -715,7 +734,7 @@ namespace ASC.Api.Settings
|
||||
return EnabledModules;
|
||||
}
|
||||
|
||||
[Read("security/password")]
|
||||
[Read("security/password", Check = false)]
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "Everyone")]
|
||||
public object GetPasswordSettings()
|
||||
{
|
||||
@ -1044,22 +1063,18 @@ namespace ASC.Api.Settings
|
||||
return StudioPeriodicNotify.ChangeSubscription(AuthContext.CurrentAccount.ID, StudioNotifyHelper);
|
||||
}
|
||||
|
||||
[Update("wizard/complete")]
|
||||
public WizardSettings CompleteWizard()
|
||||
[Update("wizard/complete", Check = false)]
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard")]
|
||||
public WizardSettings CompleteWizard(WizardModel wizardModel)
|
||||
{
|
||||
ApiContext.AuthByClaim();
|
||||
|
||||
PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
var settings = SettingsManager.Load<WizardSettings>();
|
||||
|
||||
if (settings.Completed)
|
||||
return settings;
|
||||
|
||||
settings.Completed = true;
|
||||
SettingsManager.Save(settings);
|
||||
|
||||
return settings;
|
||||
return FirstTimeTenantSettings.SaveData(wizardModel);
|
||||
}
|
||||
|
||||
|
||||
[Update("tfaapp")]
|
||||
public bool TfaSettings(TfaModel model)
|
||||
{
|
||||
@ -1337,7 +1352,7 @@ namespace ASC.Api.Settings
|
||||
return productId == Guid.Empty ? "All" : product != null ? product.Name : productId.ToString();
|
||||
}
|
||||
|
||||
[Read("license/refresh")]
|
||||
[Read("license/refresh", Check = false)]
|
||||
public bool RefreshLicense()
|
||||
{
|
||||
if (!CoreBaseSettings.Standalone) return false;
|
||||
@ -1345,6 +1360,57 @@ namespace ASC.Api.Settings
|
||||
return true;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[Read("license/required", Check = false)]
|
||||
public bool RequestLicense()
|
||||
{
|
||||
return FirstTimeTenantSettings.RequestLicense;
|
||||
}
|
||||
|
||||
|
||||
[Create("license", Check = false)]
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard")]
|
||||
public object UploadLicense([FromForm]UploadLicenseModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!AuthContext.IsAuthenticated && SettingsManager.Load<WizardSettings>().Completed) throw new SecurityException(Resource.PortalSecurity);
|
||||
if (!model.Files.Any()) throw new Exception(Resource.ErrorEmptyUploadFileSelected);
|
||||
|
||||
ApiContext.AuthByClaim();
|
||||
|
||||
var licenseFile = model.Files.First();
|
||||
var dueDate = LicenseReader.SaveLicenseTemp(licenseFile.OpenReadStream());
|
||||
|
||||
return dueDate >= DateTime.UtcNow.Date
|
||||
? Resource.LicenseUploaded
|
||||
: string.Format(Resource.LicenseUploadedOverdue,
|
||||
"",
|
||||
"",
|
||||
dueDate.Date.ToLongDateString());
|
||||
}
|
||||
catch (LicenseExpiredException ex)
|
||||
{
|
||||
Log.Error("License upload", ex);
|
||||
throw new Exception(Resource.LicenseErrorExpired);
|
||||
}
|
||||
catch (LicenseQuotaException ex)
|
||||
{
|
||||
Log.Error("License upload", ex);
|
||||
throw new Exception(Resource.LicenseErrorQuota);
|
||||
}
|
||||
catch (LicensePortalException ex)
|
||||
{
|
||||
Log.Error("License upload", ex);
|
||||
throw new Exception(Resource.LicenseErrorPortal);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("License upload", ex);
|
||||
throw new Exception(Resource.LicenseError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Read("customnavigation/getall")]
|
||||
public List<CustomNavigationItem> GetCustomNavigationItems()
|
||||
@ -1770,7 +1836,8 @@ namespace ASC.Api.Settings
|
||||
.AddCustomNamingPeopleService()
|
||||
.AddProviderManagerService()
|
||||
.AddAccountLinker()
|
||||
.AddMobileDetectorService();
|
||||
.AddMobileDetectorService()
|
||||
.AddFirstTimeTenantSettings();
|
||||
}
|
||||
}
|
||||
}
|
337
web/ASC.Web.Api/Core/FirstTimeTenantSettings.cs
Normal file
337
web/ASC.Web.Api/Core/FirstTimeTenantSettings.cs
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Billing;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.MessagingSystem;
|
||||
using ASC.Web.Api.Models;
|
||||
using ASC.Web.Core;
|
||||
using ASC.Web.Core.PublicResources;
|
||||
using ASC.Web.Core.Users;
|
||||
using ASC.Web.Core.Utility.Settings;
|
||||
using ASC.Web.Studio.Core;
|
||||
using ASC.Web.Studio.Core.Notify;
|
||||
using ASC.Web.Studio.UserControls.Management;
|
||||
using ASC.Web.Studio.Utility;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Web.Studio.UserControls.FirstTime
|
||||
{
|
||||
public class FirstTimeTenantSettings
|
||||
{
|
||||
public ILog Log { get; }
|
||||
public IConfiguration Configuration { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
public CoreSettings CoreSettings { get; }
|
||||
public TenantExtra TenantExtra { get; }
|
||||
public SettingsManager SettingsManager { get; }
|
||||
public UserManager UserManager { get; }
|
||||
public SetupInfo SetupInfo { get; }
|
||||
public SecurityContext SecurityContext { get; }
|
||||
public CookiesManager CookiesManager { get; }
|
||||
public UserManagerWrapper UserManagerWrapper { get; }
|
||||
public PaymentManager PaymentManager { get; }
|
||||
public MessageService MessageService { get; }
|
||||
public LicenseReader LicenseReader { get; }
|
||||
public StudioNotifyService StudioNotifyService { get; }
|
||||
public TimeZoneConverter TimeZoneConverter { get; }
|
||||
|
||||
public FirstTimeTenantSettings(
|
||||
IOptionsMonitor<ILog> options,
|
||||
IConfiguration configuration,
|
||||
TenantManager tenantManager,
|
||||
CoreSettings coreSettings,
|
||||
TenantExtra tenantExtra,
|
||||
SettingsManager settingsManager,
|
||||
UserManager userManager,
|
||||
SetupInfo setupInfo,
|
||||
SecurityContext securityContext,
|
||||
CookiesManager cookiesManager,
|
||||
UserManagerWrapper userManagerWrapper,
|
||||
PaymentManager paymentManager,
|
||||
MessageService messageService,
|
||||
LicenseReader licenseReader,
|
||||
StudioNotifyService studioNotifyService,
|
||||
TimeZoneConverter timeZoneConverter)
|
||||
{
|
||||
Log = options.CurrentValue;
|
||||
Configuration = configuration;
|
||||
TenantManager = tenantManager;
|
||||
CoreSettings = coreSettings;
|
||||
TenantExtra = tenantExtra;
|
||||
SettingsManager = settingsManager;
|
||||
UserManager = userManager;
|
||||
SetupInfo = setupInfo;
|
||||
SecurityContext = securityContext;
|
||||
CookiesManager = cookiesManager;
|
||||
UserManagerWrapper = userManagerWrapper;
|
||||
PaymentManager = paymentManager;
|
||||
MessageService = messageService;
|
||||
LicenseReader = licenseReader;
|
||||
StudioNotifyService = studioNotifyService;
|
||||
TimeZoneConverter = timeZoneConverter;
|
||||
}
|
||||
|
||||
public WizardSettings SaveData(WizardModel wizardModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (email, pwd, lng, timeZone, promocode, amiid, analytics) = wizardModel;
|
||||
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
var settings = SettingsManager.Load<WizardSettings>();
|
||||
if (settings.Completed)
|
||||
{
|
||||
throw new Exception("Wizard passed.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(SetupInfo.AmiMetaUrl) && IncorrectAmiId(amiid))
|
||||
{
|
||||
//throw new Exception(Resource.EmailAndPasswordIncorrectAmiId); TODO
|
||||
}
|
||||
|
||||
if (tenant.OwnerId == Guid.Empty)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromSeconds(6)); // wait cache interval
|
||||
tenant = TenantManager.GetTenant(tenant.TenantId);
|
||||
if (tenant.OwnerId == Guid.Empty)
|
||||
{
|
||||
Log.Error(tenant.TenantId + ": owner id is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
var currentUser = UserManager.GetUsers(TenantManager.GetCurrentTenant().OwnerId);
|
||||
|
||||
if (!UserManagerWrapper.ValidateEmail(email))
|
||||
{
|
||||
throw new Exception(Resource.EmailAndPasswordIncorrectEmail);
|
||||
}
|
||||
|
||||
UserManagerWrapper.CheckPasswordPolicy(pwd);
|
||||
SecurityContext.SetUserPassword(currentUser.ID, pwd);
|
||||
|
||||
email = email.Trim();
|
||||
if (currentUser.Email != email)
|
||||
{
|
||||
currentUser.Email = email;
|
||||
currentUser.ActivationStatus = EmployeeActivationStatus.NotActivated;
|
||||
}
|
||||
UserManager.SaveUserInfo(currentUser);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(promocode))
|
||||
{
|
||||
try
|
||||
{
|
||||
PaymentManager.ActivateKey(promocode);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Log.Error("Incorrect Promo: " + promocode, err);
|
||||
throw new Exception(Resource.EmailAndPasswordIncorrectPromocode);
|
||||
}
|
||||
}
|
||||
|
||||
if (RequestLicense)
|
||||
{
|
||||
TariffSettings.SetLicenseAccept(SettingsManager);
|
||||
MessageService.Send(MessageAction.LicenseKeyUploaded);
|
||||
|
||||
LicenseReader.RefreshLicense();
|
||||
}
|
||||
|
||||
if (TenantExtra.Opensource)
|
||||
{
|
||||
settings.Analytics = analytics;
|
||||
}
|
||||
settings.Completed = true;
|
||||
SettingsManager.Save(settings);
|
||||
|
||||
TrySetLanguage(tenant, lng);
|
||||
|
||||
tenant.TimeZone = TimeZoneConverter.GetTimeZone(timeZone).Id;
|
||||
|
||||
TenantManager.SaveTenant(tenant);
|
||||
|
||||
StudioNotifyService.SendCongratulations(currentUser);
|
||||
SendInstallInfo(currentUser);
|
||||
|
||||
return settings;
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
throw new Exception(UserControlsCommonResource.LicenseKeyNotFound);
|
||||
}
|
||||
catch (BillingNotConfiguredException)
|
||||
{
|
||||
throw new Exception(UserControlsCommonResource.LicenseKeyNotCorrect);
|
||||
}
|
||||
catch (BillingException)
|
||||
{
|
||||
throw new Exception(UserControlsCommonResource.LicenseException);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RequestLicense
|
||||
{
|
||||
get
|
||||
{
|
||||
return TenantExtra.EnableTarrifSettings && TenantExtra.Enterprise && !TenantExtra.EnterprisePaid;
|
||||
}
|
||||
}
|
||||
|
||||
private void TrySetLanguage(Tenant tenant, string lng)
|
||||
{
|
||||
if (string.IsNullOrEmpty(lng)) return;
|
||||
|
||||
try
|
||||
{
|
||||
var culture = CultureInfo.GetCultureInfo(lng);
|
||||
tenant.Language = culture.Name;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Log.Error(err);
|
||||
}
|
||||
}
|
||||
|
||||
private static string _amiId;
|
||||
|
||||
private bool IncorrectAmiId(string customAmiId)
|
||||
{
|
||||
customAmiId = (customAmiId ?? "").Trim();
|
||||
if (string.IsNullOrEmpty(customAmiId)) return true;
|
||||
|
||||
if (string.IsNullOrEmpty(_amiId))
|
||||
{
|
||||
var getAmiIdUrl = SetupInfo.AmiMetaUrl + "instance-id";
|
||||
var request = (HttpWebRequest)WebRequest.Create(getAmiIdUrl);
|
||||
try
|
||||
{
|
||||
using (var response = request.GetResponse())
|
||||
using (var responseStream = response.GetResponseStream())
|
||||
using (var reader = new StreamReader(responseStream))
|
||||
{
|
||||
_amiId = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
Log.Debug("Instance id: " + _amiId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Request AMI id", e);
|
||||
}
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(_amiId) || _amiId != customAmiId;
|
||||
}
|
||||
|
||||
public void SendInstallInfo(UserInfo user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = Configuration["web:install-url"];
|
||||
if (string.IsNullOrEmpty(url)) return;
|
||||
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
var q = new MailQuery
|
||||
{
|
||||
Email = user.Email,
|
||||
Id = CoreSettings.GetKey(tenant.TenantId),
|
||||
Alias = tenant.GetTenantDomain(CoreSettings),
|
||||
};
|
||||
|
||||
var index = url.IndexOf("?v=", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (0 < index)
|
||||
{
|
||||
q.Version = url.Substring(index + 3) + Environment.OSVersion;
|
||||
url = url.Substring(0, index);
|
||||
}
|
||||
|
||||
using var webClient = new WebClient();
|
||||
var values = new NameValueCollection
|
||||
{
|
||||
{"query", Signature.Create(q, "4be71393-0c90-41bf-b641-a8d9523fba5c")}
|
||||
};
|
||||
webClient.UploadValues(url, values);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
Log.Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
private class MailQuery
|
||||
{
|
||||
public string Email { get; set; }
|
||||
public string Version { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class FirstTimeTenantSettingsExtension
|
||||
{
|
||||
public static DIHelper AddFirstTimeTenantSettings(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<FirstTimeTenantSettings>();
|
||||
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
.AddCoreConfigurationService()
|
||||
.AddCoreSettingsService()
|
||||
.AddTenantExtraService()
|
||||
.AddSettingsManagerService()
|
||||
.AddSetupInfo()
|
||||
.AddSecurityContextService()
|
||||
.AddCookiesManagerService()
|
||||
.AddUserManagerWrapperService()
|
||||
.AddPaymentManagerService()
|
||||
.AddMessageServiceService()
|
||||
.AddLicenseReaderService()
|
||||
.AddStudioNotifyServiceService();
|
||||
}
|
||||
}
|
||||
}
|
@ -57,6 +57,8 @@ namespace ASC.Api.Settings
|
||||
|
||||
public bool? ThirdpartyEnable { get; set; }
|
||||
|
||||
public string WizardToken { get; set; }
|
||||
|
||||
public static SettingsWrapper GetSample()
|
||||
{
|
||||
return new SettingsWrapper
|
||||
|
11
web/ASC.Web.Api/Models/UploadLicenseModel.cs
Normal file
11
web/ASC.Web.Api/Models/UploadLicenseModel.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ASC.Web.Api.Models
|
||||
{
|
||||
public class UploadLicenseModel
|
||||
{
|
||||
public IEnumerable<IFormFile> Files { get; set; }
|
||||
}
|
||||
}
|
16
web/ASC.Web.Api/Models/WizardModel.cs
Normal file
16
web/ASC.Web.Api/Models/WizardModel.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace ASC.Web.Api.Models
|
||||
{
|
||||
public class WizardModel
|
||||
{
|
||||
public string Email { get; set; }
|
||||
public string Pwd { get; set; }
|
||||
public string Lng { get; set; }
|
||||
public string TimeZone { get; set; }
|
||||
public string Promocode { get; set; }
|
||||
public string AmiId { get; set; }
|
||||
public bool Analytics { get; set; }
|
||||
|
||||
public void Deconstruct(out string email, out string pwd, out string lng, out string timeZone, out string promocode, out string amiid, out bool analytics)
|
||||
=> (email, pwd, lng, timeZone, promocode, amiid, analytics) = (Email, Pwd, Lng, TimeZone, Promocode, AmiId, Analytics);
|
||||
}
|
||||
}
|
BIN
web/ASC.Web.Client/public/images/clouds_fond.png
Normal file
BIN
web/ASC.Web.Client/public/images/clouds_fond.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
web/ASC.Web.Client/public/images/lock.png
Normal file
BIN
web/ASC.Web.Client/public/images/lock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 B |
@ -1,35 +1,37 @@
|
||||
import React, { Suspense, lazy } from "react";
|
||||
import { Router, Route, Switch } from "react-router-dom";
|
||||
import { Loader } from "asc-web-components";
|
||||
import { history, PrivateRoute, PublicRoute, Login, Error404, StudioLayout, Offline, ComingSoon} from "asc-web-common";
|
||||
import About from "./components/pages/About";
|
||||
|
||||
const Home = lazy(() => import("./components/pages/Home"));
|
||||
const Confirm = lazy(() => import("./components/pages/Confirm"));
|
||||
const Settings = lazy(() => import("./components/pages/Settings"));
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
navigator.onLine ?
|
||||
<Router history={history}>
|
||||
<StudioLayout>
|
||||
<Suspense
|
||||
fallback={<Loader className="pageLoader" type="rombs" size='40px' />}
|
||||
>
|
||||
<Switch>
|
||||
<PublicRoute exact path={["/login","/login/error=:error", "/login/confirmed-email=:confirmedEmail"]} component={Login} />
|
||||
<Route path="/confirm" component={Confirm} />
|
||||
<PrivateRoute exact path={["/","/error=:error"]} component={Home} />
|
||||
<PrivateRoute exact path="/about" component={About} />
|
||||
<PrivateRoute restricted path="/settings" component={Settings} />
|
||||
<PrivateRoute exact path={["/coming-soon"]} component={ComingSoon} />
|
||||
<PrivateRoute component={Error404} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</StudioLayout>
|
||||
</Router> :
|
||||
<Offline/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
import React, { Suspense, lazy } from "react";
|
||||
import { Router, Route, Switch } from "react-router-dom";
|
||||
import { Loader } from "asc-web-components";
|
||||
import { history, PrivateRoute, PublicRoute, Login, Error404, StudioLayout, Offline, ComingSoon} from "asc-web-common";
|
||||
import About from "./components/pages/About";
|
||||
|
||||
const Home = lazy(() => import("./components/pages/Home"));
|
||||
const Confirm = lazy(() => import("./components/pages/Confirm"));
|
||||
const Settings = lazy(() => import("./components/pages/Settings"));
|
||||
const Wizard = lazy(() => import("./components/pages/Wizard"));
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
navigator.onLine ?
|
||||
<Router history={history}>
|
||||
<StudioLayout>
|
||||
<Suspense
|
||||
fallback={<Loader className="pageLoader" type="rombs" size='40px' />}
|
||||
>
|
||||
<Switch>
|
||||
<Route exact path="/wizard" component={Wizard} />
|
||||
<PublicRoute exact path={["/login","/login/error=:error", "/login/confirmed-email=:confirmedEmail"]} component={Login} />
|
||||
<Route path="/confirm" component={Confirm} />
|
||||
<PrivateRoute exact path={["/","/error=:error"]} component={Home} />
|
||||
<PrivateRoute exact path="/about" component={About} />
|
||||
<PrivateRoute restricted path="/settings" component={Settings} />
|
||||
<PrivateRoute exact path={["/coming-soon"]} component={ComingSoon} />
|
||||
<PrivateRoute component={Error404} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</StudioLayout>
|
||||
</Router> :
|
||||
<Offline/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
53
web/ASC.Web.Client/src/components/pages/Wizard/i18n.js
Normal file
53
web/ASC.Web.Client/src/components/pages/Wizard/i18n.js
Normal file
@ -0,0 +1,53 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: false
|
||||
},
|
||||
backend: {
|
||||
loadPath: `/locales/Wizard/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
}
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
517
web/ASC.Web.Client/src/components/pages/Wizard/index.js
Normal file
517
web/ASC.Web.Client/src/components/pages/Wizard/index.js
Normal file
@ -0,0 +1,517 @@
|
||||
import React, { Component } from 'react';
|
||||
import { withRouter } from 'react-router';
|
||||
import styled from "styled-components";
|
||||
import i18n from './i18n';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
PageLayout,
|
||||
ErrorContainer,
|
||||
history,
|
||||
constants,
|
||||
utils as commonUtils
|
||||
} from "asc-web-common";
|
||||
import {
|
||||
Loader,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
import HeaderContainer from './sub-components/header-container';
|
||||
import ButtonContainer from './sub-components/button-container';
|
||||
import SettingsContainer from './sub-components/settings-container';
|
||||
import InputContainer from './sub-components/input-container';
|
||||
import ModalContainer from './sub-components/modal-dialog-container';
|
||||
|
||||
import {
|
||||
getPortalPasswordSettings,
|
||||
getPortalTimezones,
|
||||
getPortalCultures,
|
||||
setIsWizardLoaded,
|
||||
getMachineName,
|
||||
getIsRequiredLicense,
|
||||
setPortalOwner,
|
||||
setLicense,
|
||||
resetLicenseUploaded
|
||||
} from '../../../store/wizard/actions';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
const { changeLanguage } = commonUtils;
|
||||
|
||||
const { EmailSettings } = utils.email;
|
||||
const emailSettings = new EmailSettings();
|
||||
emailSettings.allowDomainPunycode = true;
|
||||
|
||||
const WizardContainer = styled.div`
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
margin-top: 120px;
|
||||
|
||||
.wizard-form {
|
||||
margin-top: 32px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-row-gap: 32px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
}
|
||||
|
||||
@media(max-width: 520px) {
|
||||
width: calc(100% - 32px);
|
||||
margin-top: 72px
|
||||
}
|
||||
`;
|
||||
|
||||
class Body extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const { t } = props;
|
||||
|
||||
this.state = {
|
||||
password: '',
|
||||
isValidPass: false,
|
||||
errorLoading: false,
|
||||
errorMessage: null,
|
||||
errorInitWizard: null,
|
||||
sending: false,
|
||||
visibleModal: false,
|
||||
emailValid: false,
|
||||
email: '',
|
||||
changeEmail: '',
|
||||
license: false,
|
||||
languages: null,
|
||||
timezones: null,
|
||||
selectLanguage: null,
|
||||
selectTimezone: null,
|
||||
|
||||
emailNeeded: true,
|
||||
emailOwner: 'fake@mail.com',
|
||||
|
||||
hasErrorEmail: false,
|
||||
hasErrorPass: false,
|
||||
hasErrorLicense: false,
|
||||
|
||||
checkingMessages: []
|
||||
}
|
||||
|
||||
document.title = t('wizardTitle');
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const {
|
||||
t, wizardToken,
|
||||
getPortalPasswordSettings, getPortalCultures,
|
||||
getPortalTimezones, setIsWizardLoaded,
|
||||
getMachineName, getIsRequiredLicense, history
|
||||
} = this.props;
|
||||
|
||||
window.addEventListener("keyup", this.onKeyPressHandler);
|
||||
localStorage.setItem(constants.WIZARD_KEY, true);
|
||||
|
||||
if(!wizardToken) {
|
||||
history.push('/');
|
||||
} else {
|
||||
await Promise.all([
|
||||
getPortalPasswordSettings(wizardToken),
|
||||
getMachineName(wizardToken),
|
||||
getIsRequiredLicense(),
|
||||
getPortalTimezones(wizardToken)
|
||||
.then(() => {
|
||||
const { timezones, timezone } = this.props;
|
||||
const zones = this.mapTimezonesToArray(timezones);
|
||||
const select = zones.filter(zone => zone.key === timezone);
|
||||
this.setState({
|
||||
timezones: zones,
|
||||
selectTimezone: {
|
||||
key: select[0].key,
|
||||
label: select[0].label
|
||||
}
|
||||
});
|
||||
}),
|
||||
getPortalCultures()
|
||||
.then(() => {
|
||||
const { cultures, culture } = this.props;
|
||||
const languages = this.mapCulturesToArray(cultures, t);
|
||||
let select = languages.filter(lang => lang.key === culture );
|
||||
if (!select.length) select = languages.filter(lang => lang.key === 'en-US' )
|
||||
this.setState({
|
||||
languages: languages,
|
||||
selectLanguage: {
|
||||
key: select[0].key,
|
||||
label: select[0].label
|
||||
}
|
||||
})
|
||||
})
|
||||
])
|
||||
.then(() => setIsWizardLoaded(true))
|
||||
.catch((e) => {
|
||||
this.setState({
|
||||
errorInitWizard: e
|
||||
})});
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if(nextProps.isWizardLoaded === true || nextState.errorInitWizard !== null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("keyup", this.onKeyPressHandler);
|
||||
localStorage.removeItem(constants.WIZARD_KEY);
|
||||
}
|
||||
|
||||
mapTimezonesToArray = (timezones) => {
|
||||
return timezones.map((timezone) => {
|
||||
return { key: timezone.id, label: timezone.displayName };
|
||||
});
|
||||
};
|
||||
|
||||
mapCulturesToArray = (cultures, t) => {
|
||||
return cultures.map((culture) => {
|
||||
return { key: culture, label: t(`Culture_${culture}`) };
|
||||
});
|
||||
};
|
||||
|
||||
onKeyPressHandler = e => {
|
||||
if (e.key === "Enter") this.onContinueHandler();
|
||||
}
|
||||
|
||||
isValidPassHandler = val => this.setState({ isValidPass: val });
|
||||
|
||||
onChangePassword = e => this.setState({ password: e.target.value, hasErrorPass: false });
|
||||
|
||||
onClickChangeEmail = () => this.setState({ visibleModal: true });
|
||||
|
||||
onEmailChangeHandler = result => {
|
||||
const { emailNeeded } = this.state;
|
||||
|
||||
emailNeeded
|
||||
? this.setState({
|
||||
emailValid: result.isValid,
|
||||
email: result.value,
|
||||
hasErrorEmail: false
|
||||
})
|
||||
: this.setState({
|
||||
emailValid: result.isValid,
|
||||
changeEmail: result.value
|
||||
})
|
||||
}
|
||||
|
||||
onChangeLicense = () => this.setState({ license: !this.state.license });
|
||||
|
||||
onContinueHandler = () => {
|
||||
const valid = this.checkingValid();
|
||||
|
||||
if (valid) {
|
||||
const { setPortalOwner, wizardToken } = this.props;
|
||||
|
||||
const { password, email,
|
||||
selectLanguage, selectTimezone,
|
||||
emailOwner
|
||||
} = this.state;
|
||||
|
||||
this.setState({ sending: true });
|
||||
|
||||
const emailTrim = email ? email.trim() : emailOwner.trim();
|
||||
const analytics = true;
|
||||
|
||||
// console.log(emailTrim, password, selectLanguage.key, selectTimezone.key, analytics, wizardToken);
|
||||
|
||||
setPortalOwner(emailTrim, password, selectLanguage.key, selectTimezone.key, wizardToken, analytics)
|
||||
.then(() => history.push('/login'))
|
||||
.catch( e => this.setState({
|
||||
errorLoading: true,
|
||||
sending: false,
|
||||
errorMessage: e
|
||||
}))
|
||||
} else {
|
||||
this.setState({ visibleModal: true })
|
||||
}
|
||||
}
|
||||
|
||||
checkingValid = () => {
|
||||
const { t, isLicenseRequired, licenseUpload } = this.props;
|
||||
const { isValidPass, emailValid, license, emailNeeded } = this.state;
|
||||
|
||||
let checkingMessages = [];
|
||||
if(!isValidPass) {
|
||||
checkingMessages.push(t('errorPassword'));
|
||||
this.setState({hasErrorPass: true, checkingMessages: checkingMessages });
|
||||
}
|
||||
if(!license) {
|
||||
checkingMessages.push(t('errorLicenseRead'));
|
||||
this.setState({ checkingMessages: checkingMessages });
|
||||
}
|
||||
|
||||
if ( emailNeeded && !isLicenseRequired) {
|
||||
if(!emailValid) {
|
||||
checkingMessages.push(t('errorEmail'));
|
||||
this.setState({ hasErrorEmail: true, checkingMessages: checkingMessages });
|
||||
}
|
||||
|
||||
if( isValidPass && emailValid && license ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (emailNeeded && isLicenseRequired) {
|
||||
if(!emailValid) {
|
||||
checkingMessages.push(t('errorEmail'));
|
||||
this.setState({ hasErrorEmail: true, checkingMessages: checkingMessages });
|
||||
}
|
||||
|
||||
if(!licenseUpload) {
|
||||
checkingMessages.push(t('errorUploadLicenseFile'));
|
||||
this.setState({ hasErrorLicense: true, checkingMessages: checkingMessages });
|
||||
}
|
||||
|
||||
if( isValidPass && emailValid && license && licenseUpload) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emailNeeded && isLicenseRequired) {
|
||||
if(!licenseUpload) {
|
||||
checkingMessages.push(t('errorUploadLicenseFile'));
|
||||
this.setState({ hasErrorLicense: true, checkingMessages: checkingMessages });
|
||||
}
|
||||
|
||||
if( isValidPass && license && licenseUpload) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onSaveEmailHandler = () => {
|
||||
const { changeEmail, emailValid } = this.state;
|
||||
if( emailValid && changeEmail ) {
|
||||
this.setState({ email: changeEmail})
|
||||
}
|
||||
this.setState({ visibleModal: false })
|
||||
}
|
||||
|
||||
onCloseModal = () => {
|
||||
this.setState({
|
||||
visibleModal: false,
|
||||
errorLoading: false,
|
||||
errorMessage: null
|
||||
});
|
||||
}
|
||||
|
||||
onSelectTimezoneHandler = el => this.setState({ selectTimezone: el });
|
||||
|
||||
onSelectLanguageHandler = lang => this.setState({
|
||||
selectLanguage: {
|
||||
key: lang.key,
|
||||
label: lang.label
|
||||
}});
|
||||
|
||||
onInputFileHandler = file => {
|
||||
const { setLicense, wizardToken, licenseUpload, resetLicenseUploaded } = this.props;
|
||||
|
||||
if (licenseUpload) resetLicenseUploaded();
|
||||
|
||||
this.setState({ hasErrorLicense: false });
|
||||
|
||||
let fd = new FormData();
|
||||
fd.append("files", file );
|
||||
|
||||
setLicense(wizardToken, fd)
|
||||
.catch( e => this.setState({
|
||||
errorLoading: true,
|
||||
errorMessage: e,
|
||||
hasErrorLicense: true
|
||||
}))
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
isWizardLoaded,
|
||||
machineName,
|
||||
passwordSettings,
|
||||
culture,
|
||||
isLicenseRequired,
|
||||
urlLicense
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
sending,
|
||||
selectLanguage,
|
||||
license,
|
||||
selectTimezone,
|
||||
languages,
|
||||
timezones,
|
||||
emailNeeded,
|
||||
email,
|
||||
emailOwner,
|
||||
password,
|
||||
errorLoading,
|
||||
visibleModal,
|
||||
errorMessage,
|
||||
errorInitWizard,
|
||||
changeEmail,
|
||||
hasErrorEmail,
|
||||
hasErrorPass,
|
||||
hasErrorLicense,
|
||||
checkingMessages
|
||||
} = this.state;
|
||||
|
||||
console.log('wizard render');
|
||||
|
||||
if (errorInitWizard) {
|
||||
return <ErrorContainer
|
||||
headerText={t('errorInitWizardHeader')}
|
||||
bodyText={t('errorInitWizard')}
|
||||
buttonText={t('errorInitWizardButton')}
|
||||
buttonUrl="/" />
|
||||
} else if (isWizardLoaded) {
|
||||
return <WizardContainer>
|
||||
<ModalContainer t={t}
|
||||
errorLoading={errorLoading}
|
||||
visibleModal={visibleModal}
|
||||
errorMessage={errorMessage}
|
||||
emailOwner={changeEmail ? changeEmail : emailOwner}
|
||||
settings={emailSettings}
|
||||
checkingMessages={checkingMessages}
|
||||
onEmailChangeHandler={this.onEmailChangeHandler}
|
||||
onSaveEmailHandler={this.onSaveEmailHandler}
|
||||
onCloseModal={this.onCloseModal}
|
||||
/>
|
||||
|
||||
<HeaderContainer t={t} />
|
||||
|
||||
<form className='wizard-form'>
|
||||
<InputContainer t={t}s
|
||||
settingsPassword={passwordSettings}
|
||||
emailNeeded={emailNeeded}
|
||||
password={password}
|
||||
license={license}
|
||||
settings={emailSettings}
|
||||
isLicenseRequired={isLicenseRequired}
|
||||
hasErrorEmail={hasErrorEmail}
|
||||
hasErrorPass={hasErrorPass}
|
||||
hasErrorLicense={hasErrorLicense}
|
||||
urlLicense={urlLicense}
|
||||
onChangeLicense={this.onChangeLicense}
|
||||
isValidPassHandler={this.isValidPassHandler}
|
||||
onChangePassword={this.onChangePassword}
|
||||
onInputFileHandler={this.onInputFileHandler}
|
||||
onEmailChangeHandler={this.onEmailChangeHandler}
|
||||
/>
|
||||
|
||||
<SettingsContainer t={t}
|
||||
selectLanguage={selectLanguage}
|
||||
selectTimezone={selectTimezone}
|
||||
languages={languages}
|
||||
timezones={timezones}
|
||||
emailNeeded={emailNeeded}
|
||||
emailOwner={emailOwner}
|
||||
email={email}
|
||||
machineName={machineName}
|
||||
portalCulture={culture}
|
||||
onClickChangeEmail={this.onClickChangeEmail}
|
||||
onSelectLanguageHandler={this.onSelectLanguageHandler}
|
||||
onSelectTimezoneHandler={this.onSelectTimezoneHandler} />
|
||||
|
||||
<ButtonContainer t={t}
|
||||
sending={sending}
|
||||
onContinueHandler={this.onContinueHandler} />
|
||||
</form>
|
||||
</WizardContainer>
|
||||
}
|
||||
return <Loader className="pageLoader" type="rombs" size='40px' />;
|
||||
}
|
||||
}
|
||||
|
||||
Body.propTypes = {
|
||||
culture: PropTypes.string,
|
||||
i18n: PropTypes.object,
|
||||
isWizardLoaded: PropTypes.bool.isRequired,
|
||||
machineName: PropTypes.string.isRequired,
|
||||
wizardToken: PropTypes.string,
|
||||
passwordSettings: PropTypes.object,
|
||||
cultures: PropTypes.array.isRequired,
|
||||
timezones: PropTypes.array.isRequired,
|
||||
timezone: PropTypes.string.isRequired,
|
||||
licenseUpload: PropTypes.string
|
||||
}
|
||||
|
||||
const WizardWrapper = withTranslation()(Body);
|
||||
|
||||
const WizardPage = props => {
|
||||
const { isLoaded } = props;
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
return (
|
||||
<>
|
||||
{ isLoaded && <PageLayout
|
||||
sectionBodyContent={<WizardWrapper i18n={i18n} {...props} />}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
WizardPage.propTypes = {
|
||||
culture: PropTypes.string.isRequired,
|
||||
isLoaded: PropTypes.bool
|
||||
}
|
||||
|
||||
function mapStateToProps({ wizard, auth }) {
|
||||
const {
|
||||
isWizardLoaded,
|
||||
machineName,
|
||||
isLicenseRequired,
|
||||
licenseUpload
|
||||
} = wizard;
|
||||
|
||||
const {
|
||||
culture,
|
||||
wizardToken,
|
||||
passwordSettings,
|
||||
cultures,
|
||||
timezones,
|
||||
timezone,
|
||||
urlLicense
|
||||
} = auth.settings;
|
||||
|
||||
return {
|
||||
isLoaded: auth.isLoaded,
|
||||
isWizardLoaded,
|
||||
machineName,
|
||||
culture,
|
||||
wizardToken,
|
||||
passwordSettings,
|
||||
cultures,
|
||||
timezones,
|
||||
timezone,
|
||||
urlLicense,
|
||||
isLicenseRequired,
|
||||
licenseUpload
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
getPortalPasswordSettings,
|
||||
getPortalCultures,
|
||||
getPortalTimezones,
|
||||
setIsWizardLoaded,
|
||||
getMachineName,
|
||||
getIsRequiredLicense,
|
||||
setPortalOwner,
|
||||
setLicense,
|
||||
resetLicenseUploaded
|
||||
})(withRouter(WizardPage));
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
"wizardTitle": " Portal Setup - Go through these easy steps to start your web office easily",
|
||||
"welcomeTitle": "Welcome to your portal!",
|
||||
"desc": "Please setup the portal registration data.",
|
||||
"placeholderEmail": "E-mail",
|
||||
"placeholderPass": "Password",
|
||||
"placeholderLicense": "Your license file",
|
||||
"license": "Accept the terms of the ",
|
||||
"licenseLink": "License agreements",
|
||||
"domain": "Domain:",
|
||||
"email": "E-mail:",
|
||||
"language": "Language:",
|
||||
"timezone": "Time zone:",
|
||||
"buttonContinue": "Continue",
|
||||
"errorLicenseTitle": "Loading error",
|
||||
"errorLicenseBody": "The license is not valid. Make sure you select the correct file",
|
||||
"changeEmailTitle": "Change e-mail",
|
||||
"changeEmailBtn": "Save",
|
||||
|
||||
"closeModalButton": "Close",
|
||||
|
||||
"tooltipPasswordTitle": "Password must contain:",
|
||||
"tooltipPasswordLength": "-30 characters",
|
||||
"tooltipPasswordDigits": "digits",
|
||||
"tooltipPasswordCapital": "capital letters",
|
||||
"tooltipPasswordSpecial": "special characters (!@#$%^&*)",
|
||||
|
||||
"Culture_en": "English (United Kingdom)",
|
||||
"Culture_en-US": "English (United States)",
|
||||
"Culture_ru-RU": "Russian (Russia)",
|
||||
|
||||
"errorPassword": "Password does not meet the requirements",
|
||||
"errorEmail": "Invalid e-mail Address",
|
||||
"errorLicenseRead": "You must accept the terms of the license agreement",
|
||||
"errorUploadLicenseFile": "You must select a license file",
|
||||
"errorInitWizardHeader": "Something went wrong.",
|
||||
"errorInitWizard": "The service is currently unavailable, please try again later.",
|
||||
"errorInitWizardButton": "Try again",
|
||||
|
||||
"generatePassword": "Generate password",
|
||||
|
||||
"errorParamsTitle": "Registration error",
|
||||
"errorParamsBody": "Incorrect data entered:",
|
||||
"errorParamsFooter": "Close"
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
{
|
||||
"wizardTitle": "Благодарим Вас за выбор ONLYOFFICE! В целях безопасности необходимо выполнить процедуру установки пароля",
|
||||
"welcomeTitle": "Добро пожаловать на Ваш портал!",
|
||||
"desc": "Пожалуйста, введите регистрационные данные.",
|
||||
"placeholderEmail": "E-mail",
|
||||
"placeholderPass": "Пароль",
|
||||
"placeholderLicense": "Ваш файл лицензии",
|
||||
"license": "Принять условия ",
|
||||
"licenseLink": "лицензионного соглашения",
|
||||
"domain": "Домен:",
|
||||
"email": "E-mail:",
|
||||
"language": "Язык:",
|
||||
"timezone": "Часовой пояс:",
|
||||
"buttonContinue": "Продолжить",
|
||||
"errorLicenseTitle": "Ошибка загрузки",
|
||||
"errorLicenseBody": "Лицензия не действительна. Убедитесь что вы выбрали верный файл",
|
||||
"changeEmailTitle": "Измененить адрес электронной почты",
|
||||
"changeEmailBtn": "Сохранить",
|
||||
|
||||
"closeModalButton": "Закрыть",
|
||||
|
||||
"tooltipPasswordTitle": "Пароль должен содержать:",
|
||||
"tooltipPasswordLength": "-30 символов",
|
||||
"tooltipPasswordDigits": "цыфры",
|
||||
"tooltipPasswordCapital": "Заглавные буквы",
|
||||
"tooltipPasswordSpecial": "Специальные символы (!@#$%^&*)",
|
||||
|
||||
"Culture_en": "Английский (Великобритания)",
|
||||
"Culture_en-US": "Английский (США)",
|
||||
"Culture_ru-RU": "Русский (Россия)",
|
||||
|
||||
"errorPassword": "Пароль не соответсвует требованиям",
|
||||
"errorEmail": "Некорректный адрес электронной почты",
|
||||
"errorLicenseRead": "Необходимо приянть условия лицензионного соглашения",
|
||||
"errorUploadLicenseFile": "Небходим файл лицензии",
|
||||
|
||||
"errorInitWizardHeader": "Что-то пошло не так.",
|
||||
"errorInitWizard": "В данный момент сервис недоступен, попробуйте позже.",
|
||||
"errorInitWizardButton": "Попробовать снова",
|
||||
|
||||
"generatePassword": "Сгенерировать пароль",
|
||||
|
||||
"errorParamsTitle": "Ошибка регистрации",
|
||||
"errorParamsBody": "Введены некорректные данные:",
|
||||
"errorParamsFooter": "Закрыть"
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
|
||||
const StyledContainer = styled(Box)`
|
||||
width: 311px;
|
||||
margin: 0 auto;
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const ButtonContainer = ({
|
||||
t,
|
||||
sending,
|
||||
onContinueHandler
|
||||
}) => {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Button
|
||||
size="large"
|
||||
scale={true}
|
||||
primary
|
||||
isDisabled={sending}
|
||||
isLoading={sending ? true : false}
|
||||
label={t('buttonContinue')}
|
||||
onClick={onContinueHandler}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
ButtonContainer.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
sending: PropTypes.bool.isRequired,
|
||||
onContinueHandler: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default ButtonContainer;
|
@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
Box,
|
||||
Heading,
|
||||
Text,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
|
||||
const StyledHeaderContainer = styled(Box)`
|
||||
width: 100%;
|
||||
|
||||
.wizard-title {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 32px;
|
||||
line-height: 36px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wizard-desc {
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
.wizard-title, .wizard-desc {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 520px) {
|
||||
.wizard-title {
|
||||
font-size: 23px;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const HeaderContainer = ({ t }) => {
|
||||
return (
|
||||
<StyledHeaderContainer>
|
||||
<Heading level={1} title="Wizard" className="wizard-title">
|
||||
{t('welcomeTitle')}
|
||||
</Heading>
|
||||
<Text className="wizard-desc" fontSize="13px">
|
||||
{t('desc')}
|
||||
</Text>
|
||||
</StyledHeaderContainer>
|
||||
)
|
||||
};
|
||||
|
||||
HeaderContainer.propTypes = {
|
||||
t: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default HeaderContainer;
|
@ -0,0 +1,174 @@
|
||||
import React, { useRef } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
Box,
|
||||
EmailInput,
|
||||
FileInput,
|
||||
PasswordInput,
|
||||
Link,
|
||||
Checkbox,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
|
||||
const StyledContainer = styled(Box)`
|
||||
width: 311px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-row-gap: 16px;
|
||||
|
||||
.generate-pass-link {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.wizard-checkbox {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wizard-checkbox span {
|
||||
margin-right: 0.3em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.link {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const InputContainer = ({
|
||||
t,
|
||||
settingsPassword,
|
||||
emailNeeded,
|
||||
onEmailChangeHandler,
|
||||
onInputFileHandler,
|
||||
password,
|
||||
onChangePassword,
|
||||
isValidPassHandler,
|
||||
license,
|
||||
onChangeLicense,
|
||||
settings,
|
||||
isLicenseRequired,
|
||||
hasErrorEmail,
|
||||
hasErrorPass,
|
||||
hasErrorLicense,
|
||||
urlLicense
|
||||
}) => {
|
||||
const refPassInput = useRef(null);
|
||||
|
||||
const tooltipPassTitle = t('tooltipPasswordTitle');
|
||||
const tooltipPassLength = `${settingsPassword.minLength}${t('tooltipPasswordLength')}`;
|
||||
const tooltipPassDigits = settingsPassword.digits ? `${t('tooltipPasswordDigits')}` : null;
|
||||
const tooltipPassCapital = settingsPassword.upperCase ? `${t('tooltipPasswordCapital')}` : null;
|
||||
const tooltipPassSpecial = settingsPassword.specSymbols ? `${t('tooltipPasswordSpecial')}` : null;
|
||||
|
||||
const inputEmail = emailNeeded
|
||||
? <EmailInput
|
||||
name="wizard-email"
|
||||
tabIndex={1}
|
||||
size="large"
|
||||
scale={true}
|
||||
placeholder={t('email')}
|
||||
emailSettings={settings}
|
||||
hasError={hasErrorEmail}
|
||||
onValidateInput={onEmailChangeHandler}
|
||||
/>
|
||||
: null;
|
||||
|
||||
const inputLicenseFile = isLicenseRequired
|
||||
? <Box>
|
||||
<FileInput
|
||||
tabIndex={3}
|
||||
placeholder={t('placeholderLicense')}
|
||||
size="large"
|
||||
scale={true}
|
||||
accept=".lic"
|
||||
hasError={hasErrorLicense}
|
||||
onInput={onInputFileHandler}
|
||||
/>
|
||||
</Box>
|
||||
: null;
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
{inputEmail}
|
||||
|
||||
<PasswordInput
|
||||
ref={refPassInput}
|
||||
tabIndex={2}
|
||||
size="large"
|
||||
scale={true}
|
||||
inputValue={password}
|
||||
passwordSettings={settingsPassword}
|
||||
isDisabled={false}
|
||||
placeholder={t('placeholderPass')}
|
||||
hideNewPasswordButton={true}
|
||||
isDisableTooltip={true}
|
||||
isTextTooltipVisible={true}
|
||||
hasError={hasErrorPass}
|
||||
tooltipPasswordTitle={tooltipPassTitle}
|
||||
tooltipPasswordLength={tooltipPassLength}
|
||||
tooltipPasswordDigits={tooltipPassDigits}
|
||||
tooltipPasswordCapital={tooltipPassCapital}
|
||||
tooltipPasswordSpecial={tooltipPassSpecial}
|
||||
onChange={onChangePassword}
|
||||
onValidateInput={isValidPassHandler}
|
||||
/>
|
||||
{ inputLicenseFile }
|
||||
{!isLicenseRequired
|
||||
? <Link
|
||||
className='generate-pass-link'
|
||||
type="action"
|
||||
fontWeight="600"
|
||||
isHovered={true}
|
||||
onClick={() => refPassInput.current.onGeneratePassword()}>
|
||||
{t('generatePassword')}
|
||||
</Link>
|
||||
: null
|
||||
}
|
||||
<Box>
|
||||
<Checkbox
|
||||
className="wizard-checkbox"
|
||||
id="license"
|
||||
name="confirm"
|
||||
label={t('license')}
|
||||
isChecked={license}
|
||||
isDisabled={false}
|
||||
onChange={onChangeLicense}
|
||||
/>
|
||||
<Link
|
||||
className="link"
|
||||
type="page"
|
||||
color="#116d9d"
|
||||
fontSize="13px"
|
||||
target="_blank"
|
||||
href={urlLicense ? urlLicense : "https://gnu.org/licenses/gpl-3.0.html"}
|
||||
isBold={false}
|
||||
>{t('licenseLink')}</Link>
|
||||
</Box>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
InputContainer.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
settingsPassword: PropTypes.object.isRequired,
|
||||
emailNeeded: PropTypes.bool.isRequired,
|
||||
onEmailChangeHandler: PropTypes.func.isRequired,
|
||||
onInputFileHandler: PropTypes.func.isRequired,
|
||||
password: PropTypes.string.isRequired,
|
||||
onChangePassword: PropTypes.func.isRequired,
|
||||
isValidPassHandler: PropTypes.func.isRequired,
|
||||
license: PropTypes.bool.isRequired,
|
||||
onChangeLicense: PropTypes.func.isRequired,
|
||||
urlLicense: PropTypes.string
|
||||
};
|
||||
|
||||
export default InputContainer;
|
@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
ModalDialog,
|
||||
EmailInput,
|
||||
Button,
|
||||
Box,
|
||||
Text,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
|
||||
const BtnContainer = styled(Box)`
|
||||
width: 100px;
|
||||
|
||||
@media ${tablet} {
|
||||
width: 293px;
|
||||
}
|
||||
`;
|
||||
|
||||
const BodyContainer = styled(Box)`
|
||||
font: 13px 'Open Sans', normal;
|
||||
line-height: 20px;
|
||||
`;
|
||||
|
||||
const ModalContainer = ({
|
||||
t,
|
||||
errorLoading,
|
||||
visibleModal,
|
||||
errorMessage,
|
||||
emailOwner,
|
||||
settings,
|
||||
onEmailChangeHandler,
|
||||
onSaveEmailHandler,
|
||||
onCloseModal,
|
||||
checkingMessages
|
||||
}) => {
|
||||
|
||||
let header, content, footer;
|
||||
|
||||
const visible = errorLoading ? errorLoading : visibleModal;
|
||||
|
||||
if(errorLoading) {
|
||||
header = t('errorLicenseTitle');
|
||||
content = <BodyContainer>
|
||||
{ errorMessage
|
||||
? errorMessage
|
||||
: t('errorLicenseBody')}
|
||||
</BodyContainer>;
|
||||
|
||||
} else if( visibleModal && checkingMessages.length < 1) {
|
||||
header = t('changeEmailTitle');
|
||||
|
||||
content = <EmailInput
|
||||
tabIndex={1}
|
||||
scale={true}
|
||||
size='base'
|
||||
id="change-email"
|
||||
name="email-wizard"
|
||||
placeholder={t('placeholderEmail')}
|
||||
emailSettings={settings}
|
||||
value={emailOwner}
|
||||
onValidateInput={onEmailChangeHandler}
|
||||
/>;
|
||||
|
||||
footer = <BtnContainer>
|
||||
<Button
|
||||
key="saveBtn"
|
||||
label={t('changeEmailBtn')}
|
||||
primary={true}
|
||||
scale={true}
|
||||
size="big"
|
||||
onClick={onSaveEmailHandler}
|
||||
/>
|
||||
</BtnContainer>;
|
||||
} else if ( visibleModal && checkingMessages.length > 0) {
|
||||
header = t('errorParamsTitle');
|
||||
|
||||
content = <>
|
||||
<Text as="p">{ t('errorParamsBody') }</Text>
|
||||
{
|
||||
checkingMessages.map((el, index) => <Text key={index} as="p">- {el};</Text>)
|
||||
}
|
||||
</>;
|
||||
|
||||
footer = <BtnContainer>
|
||||
<Button
|
||||
key="saveBtn"
|
||||
label={t('errorParamsFooter')}
|
||||
primary={true}
|
||||
scale={true}
|
||||
size="big"
|
||||
onClick={onCloseModal} />
|
||||
</BtnContainer>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
displayType="auto"
|
||||
zIndex={310}
|
||||
headerContent={header}
|
||||
bodyContent={content}
|
||||
footerContent={footer}
|
||||
onClose={onCloseModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ModalContainer.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
errorLoading: PropTypes.bool.isRequired,
|
||||
visibleModal: PropTypes.bool.isRequired,
|
||||
emailOwner: PropTypes.string,
|
||||
settings: PropTypes.object.isRequired,
|
||||
onEmailChangeHandler: PropTypes.func.isRequired,
|
||||
onSaveEmailHandler: PropTypes.func.isRequired,
|
||||
onCloseModal: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ModalContainer;
|
@ -0,0 +1,130 @@
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
Box,
|
||||
ComboBox,
|
||||
Text,
|
||||
Link,
|
||||
utils
|
||||
} from 'asc-web-components';
|
||||
|
||||
const { tablet } = utils.device;
|
||||
|
||||
const StyledContainer = styled(Box)`
|
||||
width: 311px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto;
|
||||
grid-auto-columns: min-content;
|
||||
grid-row-gap: 12px;
|
||||
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.machine-name-value,
|
||||
.email-value {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.drop-down {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const SettingsContainer = ({
|
||||
selectLanguage,
|
||||
selectTimezone,
|
||||
languages,
|
||||
timezones,
|
||||
emailNeeded,
|
||||
email,
|
||||
emailOwner,
|
||||
t,
|
||||
machineName,
|
||||
onClickChangeEmail,
|
||||
onSelectLanguageHandler,
|
||||
onSelectTimezoneHandler
|
||||
}) => {
|
||||
|
||||
const titleEmail = !emailNeeded
|
||||
? <Text>{t('email')}</Text>
|
||||
: null
|
||||
|
||||
const contentEmail = !emailNeeded
|
||||
? <Link
|
||||
className="email-value"
|
||||
type="action"
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
isHovered={true}
|
||||
onClick={onClickChangeEmail}
|
||||
>
|
||||
{email ? email : emailOwner}
|
||||
</Link>
|
||||
: null
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<Text fontSize="13px">{t('domain')}</Text>
|
||||
<Text className="machine-name-value" fontSize="13px" fontWeight="600">{machineName}</Text>
|
||||
|
||||
{titleEmail}
|
||||
{contentEmail}
|
||||
|
||||
<Text fontSize="13px">{t('language')}</Text>
|
||||
<ComboBox
|
||||
className="drop-down"
|
||||
options={languages}
|
||||
selectedOption={{
|
||||
key: selectLanguage.key,
|
||||
label: selectLanguage.label
|
||||
}}
|
||||
noBorder={true}
|
||||
scaled={false}
|
||||
size='content'
|
||||
dropDownMaxHeight={300}
|
||||
onSelect={onSelectLanguageHandler}
|
||||
/>
|
||||
|
||||
<Text className="title" fontSize="13px">{t('timezone')}</Text>
|
||||
<ComboBox
|
||||
className="drop-down"
|
||||
options={timezones}
|
||||
selectedOption={{
|
||||
key: selectTimezone.key,
|
||||
label: selectTimezone.label
|
||||
}}
|
||||
noBorder={true}
|
||||
dropDownMaxHeight={300}
|
||||
scaled={false}
|
||||
size='content'
|
||||
onSelect={onSelectTimezoneHandler}
|
||||
/>
|
||||
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
SettingsContainer.propTypes = {
|
||||
selectLanguage: PropTypes.object.isRequired,
|
||||
selectTimezone: PropTypes.object.isRequired,
|
||||
languages: PropTypes.array.isRequired,
|
||||
timezones: PropTypes.array.isRequired,
|
||||
emailNeeded: PropTypes.bool.isRequired,
|
||||
emailOwner: PropTypes.string,
|
||||
t: PropTypes.func.isRequired,
|
||||
machineName: PropTypes.string.isRequired,
|
||||
email: PropTypes.string,
|
||||
onClickChangeEmail: PropTypes.func.isRequired,
|
||||
onSelectLanguageHandler: PropTypes.func.isRequired,
|
||||
onSelectTimezoneHandler: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default SettingsContainer;
|
@ -6,11 +6,13 @@ import "./custom.scss";
|
||||
import App from "./App";
|
||||
import * as serviceWorker from "./serviceWorker";
|
||||
import { store as commonStore, constants, history, ErrorBoundary} from "asc-web-common";
|
||||
|
||||
const {
|
||||
getUserInfo,
|
||||
getPortalSettings,
|
||||
setIsLoaded
|
||||
} = commonStore.auth.actions;
|
||||
|
||||
const { AUTH_KEY } = constants;
|
||||
|
||||
const token = localStorage.getItem(AUTH_KEY);
|
||||
@ -19,6 +21,7 @@ if (!token) {
|
||||
getPortalSettings(store.dispatch)
|
||||
.then(() => store.dispatch(setIsLoaded(true)))
|
||||
.catch(e => history.push(`/login/error=${e}`));
|
||||
|
||||
} else if (!window.location.pathname.includes("confirm/EmailActivation")) {
|
||||
getUserInfo(store.dispatch)
|
||||
.then(() => store.dispatch(setIsLoaded(true)))
|
||||
|
@ -2,12 +2,15 @@ import { combineReducers } from 'redux';
|
||||
import settingsReducer from './settings/reducer';
|
||||
import confirmReducer from './confirm/reducer';
|
||||
import { store } from 'asc-web-common';
|
||||
import wizardReducer from './wizard/reducer';
|
||||
|
||||
const { reducer: authReducer } = store.auth;
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
settings: settingsReducer,
|
||||
confirm: confirmReducer
|
||||
confirm: confirmReducer,
|
||||
wizard: wizardReducer
|
||||
});
|
||||
|
||||
export default rootReducer;
|
103
web/ASC.Web.Client/src/store/wizard/actions.js
Normal file
103
web/ASC.Web.Client/src/store/wizard/actions.js
Normal file
@ -0,0 +1,103 @@
|
||||
import { store, api } from "asc-web-common";
|
||||
const {
|
||||
setPasswordSettings,
|
||||
setTimezones,
|
||||
setPortalCultures,
|
||||
getPortalSettings,
|
||||
setWizardComplete
|
||||
} = store.auth.actions;
|
||||
|
||||
export const SET_IS_WIZARD_LOADED = 'SET_IS_WIZARD_LOADED';
|
||||
export const SET_IS_MACHINE_NAME = 'SET_IS_MACHINE_NAME';
|
||||
export const SET_IS_LICENSE_REQUIRED = "SET_IS_LICENSE_REQUIRED";
|
||||
export const SET_LICENSE_UPLOAD = "SET_LICENSE_UPLOAD";
|
||||
export const RESET_LICENSE_UPLOADED = "RESET_LICENSE_UPLOADED";
|
||||
|
||||
export function setIsWizardLoaded(isWizardLoaded) {
|
||||
return {
|
||||
type: SET_IS_WIZARD_LOADED,
|
||||
isWizardLoaded
|
||||
};
|
||||
};
|
||||
|
||||
export function setMachineName(machineName) {
|
||||
return {
|
||||
type: SET_IS_MACHINE_NAME,
|
||||
machineName
|
||||
};
|
||||
}
|
||||
|
||||
export function setIsRequiredLicense(isRequired) {
|
||||
return {
|
||||
type: SET_IS_LICENSE_REQUIRED,
|
||||
isRequired
|
||||
}
|
||||
}
|
||||
|
||||
export function setLicenseUpload(message) {
|
||||
return {
|
||||
type: SET_LICENSE_UPLOAD,
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
export function resetLicenseUploaded() {
|
||||
return {
|
||||
type: RESET_LICENSE_UPLOADED
|
||||
}
|
||||
}
|
||||
|
||||
export function getPortalPasswordSettings(token) {
|
||||
return dispatch => {
|
||||
return api.settings.getPortalPasswordSettings(token).then(settings => {
|
||||
dispatch(setPasswordSettings(settings));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function getPortalTimezones(token) {
|
||||
return dispatch => {
|
||||
return api.settings.getPortalTimezones(token).then(timezones => {
|
||||
dispatch(setTimezones(timezones));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function getPortalCultures() {
|
||||
return dispatch => {
|
||||
return api.settings.getPortalCultures().then(cultures => {
|
||||
dispatch(setPortalCultures(cultures));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function getMachineName(token) {
|
||||
return dispatch => {
|
||||
return api.settings.getMachineName(token).then(machineName => {
|
||||
dispatch(setMachineName(machineName));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function setPortalOwner(email, pwd, lng, timeZone, confirmKey, analytics) {
|
||||
return dispatch => {
|
||||
return api.settings.setPortalOwner(email, pwd, lng, timeZone, confirmKey, analytics)
|
||||
.then(() => dispatch(setWizardComplete()))
|
||||
.then(() => getPortalSettings(dispatch))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function getIsRequiredLicense() {
|
||||
return dispatch => {
|
||||
return api.settings.getIsLicenseRequired()
|
||||
.then(isRequired => dispatch(setIsRequiredLicense(isRequired)))
|
||||
}
|
||||
}
|
||||
|
||||
export function setLicense(confirmKey, data) {
|
||||
return dispatch => {
|
||||
return api.settings.setLicense(confirmKey, data)
|
||||
.then(res => dispatch(setLicenseUpload(res)))
|
||||
}
|
||||
}
|
49
web/ASC.Web.Client/src/store/wizard/reducer.js
Normal file
49
web/ASC.Web.Client/src/store/wizard/reducer.js
Normal file
@ -0,0 +1,49 @@
|
||||
import {
|
||||
SET_IS_WIZARD_LOADED,
|
||||
SET_IS_MACHINE_NAME,
|
||||
SET_IS_LICENSE_REQUIRED,
|
||||
SET_LICENSE_UPLOAD,
|
||||
RESET_LICENSE_UPLOADED
|
||||
} from "./actions";
|
||||
|
||||
const initState = {
|
||||
isWizardLoaded: false,
|
||||
isLicenseRequired: false,
|
||||
machineName: 'unknown',
|
||||
licenseUpload: null
|
||||
};
|
||||
|
||||
const ownerReducer = ( state = initState, action) => {
|
||||
switch(action.type) {
|
||||
|
||||
case SET_IS_WIZARD_LOADED:
|
||||
return Object.assign({}, state, {
|
||||
isWizardLoaded: action.isWizardLoaded
|
||||
});
|
||||
|
||||
case SET_IS_MACHINE_NAME:
|
||||
return Object.assign({}, state, {
|
||||
machineName: action.machineName
|
||||
});
|
||||
|
||||
case SET_IS_LICENSE_REQUIRED:
|
||||
return Object.assign({}, state, {
|
||||
isLicenseRequired: action.isRequired
|
||||
});
|
||||
|
||||
case SET_LICENSE_UPLOAD:
|
||||
return Object.assign({}, state, {
|
||||
licenseUpload: action.message
|
||||
})
|
||||
|
||||
case RESET_LICENSE_UPLOADED:
|
||||
return Object.assign({}, state, {
|
||||
licenseUpload: null
|
||||
})
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default ownerReducer;
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-common",
|
||||
"version": "1.0.95",
|
||||
"version": "1.0.96",
|
||||
"description": "Ascensio System SIA common components and solutions library",
|
||||
"license": "AGPL-3.0",
|
||||
"files": [
|
||||
|
@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { AUTH_KEY } from "../constants";
|
||||
import { AUTH_KEY, WIZARD_KEY } from "../constants";
|
||||
|
||||
const PREFIX = "api";
|
||||
const VERSION = "2.0";
|
||||
@ -22,6 +22,9 @@ client.interceptors.response.use(
|
||||
return response;
|
||||
},
|
||||
error => {
|
||||
if(localStorage.getItem(WIZARD_KEY))
|
||||
return;
|
||||
|
||||
if (error.response.status === 401) {
|
||||
setAuthorizationToken();
|
||||
window.location.href = "/login/error=unauthorized";
|
||||
|
@ -26,11 +26,16 @@ export function getSettings() {
|
||||
return request(options);
|
||||
}
|
||||
|
||||
export function getPortalTimezones() {
|
||||
return request({
|
||||
export function getPortalTimezones(confirmKey = null) {
|
||||
const options = {
|
||||
method: "get",
|
||||
url: "/settings/timezones.json"
|
||||
});
|
||||
};
|
||||
|
||||
if(confirmKey)
|
||||
options.headers = { confirm: confirmKey };
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
||||
export function setLanguageAndTime(lng, timeZoneID) {
|
||||
@ -99,4 +104,56 @@ export function getSettings() {
|
||||
url: `/settings/sendjoininvite`,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function getMachineName(confirmKey = null) {
|
||||
const options = {
|
||||
method: "get",
|
||||
url: "/settings/machine.json"
|
||||
};
|
||||
|
||||
if ( confirmKey )
|
||||
options.headers = { confirm: confirmKey };
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
||||
export function setPortalOwner( email, pwd, lng, timeZone, confirmKey = null, analytics ) {
|
||||
const options = {
|
||||
method: "put",
|
||||
url: "/settings/wizard/complete.json",
|
||||
data: {
|
||||
email: email,
|
||||
pwd: pwd,
|
||||
lng: lng,
|
||||
timeZone: timeZone,
|
||||
analytics: analytics
|
||||
}
|
||||
}
|
||||
|
||||
if ( confirmKey ) {
|
||||
options.headers = { confirm: confirmKey};
|
||||
}
|
||||
return request(options);
|
||||
}
|
||||
|
||||
export function getIsLicenseRequired() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/settings/license/required.json'
|
||||
})
|
||||
}
|
||||
|
||||
export function setLicense(confirmKey = null, data) {
|
||||
const options = {
|
||||
method: "post",
|
||||
url: `/settings/license`,
|
||||
data
|
||||
}
|
||||
|
||||
if ( confirmKey ) {
|
||||
options.headers = { confirm: confirmKey }
|
||||
}
|
||||
|
||||
return request(options);
|
||||
}
|
@ -49,7 +49,7 @@ const Header = styled.header`
|
||||
}
|
||||
`;
|
||||
|
||||
const HeaderUnauth = ({ t, enableAdmMess }) => {
|
||||
const HeaderUnauth = ({ t, enableAdmMess, wizardToken }) => {
|
||||
|
||||
//console.log("Header render");
|
||||
|
||||
@ -68,7 +68,7 @@ const HeaderUnauth = ({ t, enableAdmMess }) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{enableAdmMess && <RecoverAccess t={t} />}
|
||||
{(enableAdmMess && !wizardToken) && <RecoverAccess t={t} />}
|
||||
</div>
|
||||
</Box>
|
||||
</Header>
|
||||
@ -79,12 +79,14 @@ HeaderUnauth.displayName = "Header";
|
||||
|
||||
HeaderUnauth.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
enableAdmMess: PropTypes.bool.isRequired
|
||||
enableAdmMess: PropTypes.bool,
|
||||
wizardToken: PropTypes.string
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
enableAdmMess: state.auth.settings.enableAdmMess
|
||||
enableAdmMess: state.auth.settings.enableAdmMess,
|
||||
wizardToken: state.auth.settings.wizardToken
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,24 +16,15 @@ const PrivateRoute = ({ component: Component, ...rest }) => {
|
||||
restricted,
|
||||
allowForMe,
|
||||
currentUser,
|
||||
computedMatch
|
||||
computedMatch,
|
||||
wizardToken
|
||||
} = rest;
|
||||
|
||||
const { userId } = computedMatch.params;
|
||||
const token = localStorage.getItem(AUTH_KEY);
|
||||
|
||||
const renderComponent = useCallback(
|
||||
props => {
|
||||
if (!token || (isLoaded && !isAuthenticated)) {
|
||||
return (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: "/login",
|
||||
state: { from: props.location }
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isLoaded) {
|
||||
return (
|
||||
<PageLayout
|
||||
@ -44,6 +35,17 @@ const PrivateRoute = ({ component: Component, ...rest }) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (!token || (isLoaded && !isAuthenticated)) {
|
||||
return (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: "/login",
|
||||
state: { from: props.location }
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!restricted ||
|
||||
isAdmin ||
|
||||
@ -66,11 +68,12 @@ const PrivateRoute = ({ component: Component, ...rest }) => {
|
||||
allowForMe,
|
||||
currentUser,
|
||||
userId,
|
||||
wizardToken,
|
||||
Component
|
||||
]
|
||||
);
|
||||
|
||||
// console.log("PrivateRoute render", rest);
|
||||
console.log("PrivateRoute render", rest);
|
||||
return <Route {...rest} render={renderComponent} />;
|
||||
};
|
||||
|
||||
@ -79,7 +82,8 @@ function mapStateToProps(state) {
|
||||
isAuthenticated: state.auth.isAuthenticated,
|
||||
isLoaded: state.auth.isLoaded,
|
||||
isAdmin: isAdmin(state.auth.user),
|
||||
currentUser: state.auth.user
|
||||
currentUser: state.auth.user,
|
||||
wizardToken: state.auth.settings.wizardToken
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,15 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Redirect, Route } from 'react-router-dom';
|
||||
import { AUTH_KEY } from "../../constants";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export const PublicRoute = ({ component: Component, ...rest }) => {
|
||||
const token = localStorage.getItem(AUTH_KEY);
|
||||
|
||||
const {wizardToken, wizardCompleted} = rest;
|
||||
|
||||
const renderComponent = useCallback(
|
||||
props => {
|
||||
props => {
|
||||
if(token) {
|
||||
return (
|
||||
<Redirect
|
||||
@ -19,9 +22,19 @@ export const PublicRoute = ({ component: Component, ...rest }) => {
|
||||
);
|
||||
}
|
||||
|
||||
return <Component {...props} />;
|
||||
}, [token, Component]);
|
||||
if(wizardToken && !wizardCompleted) {
|
||||
return (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: "/wizard",
|
||||
state: { from: props.location }
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <Component {...props} />;
|
||||
}, [token, wizardToken, Component]);
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
@ -29,4 +42,12 @@ export const PublicRoute = ({ component: Component, ...rest }) => {
|
||||
/>
|
||||
)
|
||||
};
|
||||
export default PublicRoute;
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
wizardToken: state.auth.settings.wizardToken,
|
||||
wizardCompleted: state.auth.settings.wizardCompleted
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(PublicRoute);
|
@ -1,6 +1,7 @@
|
||||
export const AUTH_KEY = 'asc_auth_key';
|
||||
export const LANGUAGE = 'language';
|
||||
export const ARTICLE_PINNED_KEY = 'asc_article_pinned_key';
|
||||
export const WIZARD_KEY = 'asc_wizard_key';
|
||||
|
||||
/**
|
||||
* Enum for employee activation status.
|
||||
|
@ -15,6 +15,7 @@ export const SET_CURRENT_PRODUCT_ID = "SET_CURRENT_PRODUCT_ID";
|
||||
export const SET_CURRENT_PRODUCT_HOME_PAGE = "SET_CURRENT_PRODUCT_HOME_PAGE";
|
||||
export const SET_GREETING_SETTINGS = "SET_GREETING_SETTINGS";
|
||||
export const SET_CUSTOM_NAMES = "SET_CUSTOM_NAMES";
|
||||
export const SET_WIZARD_COMPLETED ="SET_WIZARD_COMPLETED";
|
||||
|
||||
export function setCurrentUser(user) {
|
||||
return {
|
||||
@ -114,6 +115,12 @@ export function setCustomNames(customNames) {
|
||||
};
|
||||
}
|
||||
|
||||
export function setWizardComplete() {
|
||||
return {
|
||||
type: SET_WIZARD_COMPLETED
|
||||
}
|
||||
}
|
||||
|
||||
export function getUser(dispatch) {
|
||||
return api.people.getUser()
|
||||
.then(user => dispatch(setCurrentUser(user)))
|
||||
@ -181,4 +188,4 @@ export function getPortalPasswordSettings(dispatch, confirmKey = null) {
|
||||
return api.settings.getPortalPasswordSettings(confirmKey).then(settings => {
|
||||
dispatch(setPasswordSettings(settings));
|
||||
});
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
SET_CURRENT_USER, SET_MODULES, SET_SETTINGS, SET_IS_LOADED, LOGOUT, SET_PASSWORD_SETTINGS, SET_NEW_EMAIL,
|
||||
SET_PORTAL_CULTURES, SET_PORTAL_LANGUAGE_AND_TIME, SET_TIMEZONES, SET_CURRENT_PRODUCT_ID, SET_CURRENT_PRODUCT_HOME_PAGE, SET_GREETING_SETTINGS,
|
||||
SET_CUSTOM_NAMES } from './actions';
|
||||
SET_CUSTOM_NAMES, SET_WIZARD_COMPLETED } from './actions';
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
import { LANGUAGE, AUTH_KEY } from '../../constants';
|
||||
|
||||
@ -30,7 +30,8 @@ const initialState = {
|
||||
timePattern: "h:mm tt"
|
||||
},
|
||||
greetingSettings: 'Web Office Applications',
|
||||
enableAdmMess: false
|
||||
enableAdmMess: false,
|
||||
urlLicense: "https://gnu.org/licenses/gpl-3.0.html"
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,6 +103,12 @@ const authReducer = (state = initialState, action) => {
|
||||
return Object.assign({}, initialState, {
|
||||
settings: state.settings
|
||||
});
|
||||
case SET_WIZARD_COMPLETED:
|
||||
return Object.assign({}, state, {
|
||||
settings: { ...state.settings, wizardCompleted: true}
|
||||
})
|
||||
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.374",
|
||||
"version": "1.0.375",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
|
@ -30,7 +30,7 @@ const hoverCss = css`
|
||||
`;
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const ButtonWrapper = ({primary, scale, size, isHovered, isClicked, isDisabled, isLoading, label, innerRef, ...props}) => <button ref={innerRef} type="button" {...props}></button>;
|
||||
const ButtonWrapper = ({primary, scale, size, isHovered, isClicked, isDisabled, isLoading, label, innerRef, minWidth, ...props}) => <button ref={innerRef} type="button" {...props}></button>;
|
||||
|
||||
ButtonWrapper.propTypes = {
|
||||
label: PropTypes.string,
|
||||
|
@ -120,7 +120,10 @@ class FileInput extends Component {
|
||||
fileName: this.inputRef.current.files[0].name,
|
||||
file: this.inputRef.current.files[0]
|
||||
}, () => {
|
||||
if(onInput) onInput(this.state.file);
|
||||
if(onInput) {
|
||||
this.inputRef.current.value = '';
|
||||
onInput(this.state.file);
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ const StyledInput = styled(SimpleInput)`
|
||||
line-height: 32px;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media ${tablet} {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@ -48,16 +47,13 @@ const StyledInput = styled(SimpleInput)`
|
||||
|
||||
const PasswordProgress = styled.div`
|
||||
${props => (props.inputWidth ? `width: ${props.inputWidth};` : `flex: auto;`)}
|
||||
|
||||
.input-relative {
|
||||
position: relative;
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
@ -68,13 +64,11 @@ const PasswordProgress = styled.div`
|
||||
const NewPasswordButton = styled.div`
|
||||
margin: 0 16px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -82,7 +76,6 @@ const NewPasswordButton = styled.div`
|
||||
|
||||
const CopyLink = styled.div`
|
||||
margin-top: -6px;
|
||||
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
margin-left: 0px;
|
||||
@ -579,6 +572,7 @@ PasswordInput.propTypes = {
|
||||
tooltipPasswordSpecial: PropTypes.string,
|
||||
|
||||
generatorSpecial: PropTypes.string,
|
||||
NewPasswordButtonVisible: PropTypes.bool,
|
||||
passwordSettings: PropTypes.object.isRequired,
|
||||
|
||||
onValidateInput: PropTypes.func,
|
||||
@ -613,4 +607,4 @@ PasswordInput.defaultProps = {
|
||||
simpleView: false
|
||||
};
|
||||
|
||||
export default PasswordInput;
|
||||
export default PasswordInput;
|
@ -8,7 +8,6 @@ export { default as Button } from './components/button'
|
||||
export { default as Calendar } from './components/calendar'
|
||||
export { default as Checkbox } from './components/checkbox'
|
||||
export { default as ComboBox } from './components/combobox'
|
||||
export { default as ContextMenu } from './components/context-menu'
|
||||
export { default as ContextMenuButton } from './components/context-menu-button'
|
||||
export { default as CustomScrollbarsVirtualList } from './components/scrollbar/custom-scrollbars-virtual-list'
|
||||
export { default as DatePicker } from './components/date-picker'
|
||||
@ -55,4 +54,4 @@ export { default as Tooltip } from './components/tooltip'
|
||||
export { default as TreeMenu } from './components/tree-menu'
|
||||
export { default as TreeNode } from './components/tree-menu/sub-components/tree-node'
|
||||
export { default as utils } from './utils'
|
||||
export { Icons } from './components/icons'
|
||||
export { Icons } from './components/icons'
|
11741
web/ASC.Web.Core/PublicResources/Resource.Designer.cs
generated
11741
web/ASC.Web.Core/PublicResources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Administratorbenachrichtigungen</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Ihre Nachricht wurde erfolgreich gesendet. Der Portaladministrator wird Sie kontaktieren.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Der Link zum Bestätigen der Operation wurde an :email verschickt (die E-Mail-Adresse des Portalbesitzers).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Einstellbar</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Falsche E-Mail-Adresse</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Ungültiger Werbecode</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>Diese Einstellungen wurden erfolgreich gespeichert</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>Keine Berechtigung zum Durchführen dieser Aktion</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>Ein Benutzer mit dieser E-Mail-Adresse ist bereits registriert</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>Die Registrierung der E-Mails von dieser Domäne ist verboten</value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Das Feld für die E-Mail-Adresse ist leer</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>Die aktuelle E-Mail-Adresse und die neue sind gleich</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Der Nachrichtentext ist leer</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>Die hochgeladene Datei konnte nicht gefunden werden</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>Ungültige E-Mail-Adresse</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Ungültiger Domain-Name</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>Das Feld "Kennwort" ist leer.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>Großbuchstaben</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Anforderungslimit wurde überschritten</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>Der Benutzer konnte nicht gefunden werden</value>
|
||||
</data>
|
||||
@ -213,12 +178,33 @@
|
||||
<data name="FileSizePostfix" xml:space="preserve">
|
||||
<value>Byte,KB,MB,GB,TB</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>Der Link zum Bestätigen Ihres Kontos wurde an die angegebene E-Mail-Adresse geschickt</value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>Fehler des Servers beim Speichern der Einstellungsdaten</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Zu viele LDAP-Operationen.</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>Lizenz ist nicht korrekt</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>Lizenz ist abgelaufen </value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>Die Anzahl der Portale übersteigt die zugelassene Lizenz</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>Die Anzahl der Benutzer übersteigt die zugelassene Lizenz</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Erfolgreich hochgeladen </value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Erfolgreich hochgeladen. {0}Support und Updates sind ab dieser Lizenz nicht mehr verfügbar {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>Die Hinweise für die Änderung der E-Mail-Adresse wurden erfolgreich gesendet</value>
|
||||
</data>
|
||||
@ -234,6 +220,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Der verfügbare Speicherplatz ist überschritten</value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Zugang zum Portal</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Das Profil wurde gelöscht</value>
|
||||
</data>
|
||||
|
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Nofificaciones de administradores</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Su mensaje fue enviado con éxito. El administrador del portal se pondrá en contacto con usted.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un enlace para confirmar la operación ha sido enviada al :correo electrónico (la dirección del correo electrónico del propietario del portal).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Personalizado</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Dirección de correo electrónico incorrecta</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Código de promocional incorrecto</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>Estos ajustes han sido guardados con éxito</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>No hay permisos para realizar esta acción</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>{!User} con este correo electrónico ya está registrado</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>No se permite el registro para los correos electrónicos de este dominio </value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Campo de correo electrónico está vacío</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>El correo electrónico actual y el nuevo correo electrónico son iguales</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Texto del mensaje está vacío</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>Imposible encontrar el archivo subido</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>E-mail inválido</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Nombre de dominio inválido</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>La contraseña está vacía.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>letras mayúsculas</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Límite de solicitudes es excedido</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>Usuario no ha sido encontrado</value>
|
||||
</data>
|
||||
@ -213,12 +178,33 @@
|
||||
<data name="FileSizePostfix" xml:space="preserve">
|
||||
<value>bytes,KB,MB,GB,TB</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>El enlace para confirmar su cuenta ha sido enviado al e-mail especificado. </value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>El servidor no pudo guardar ajustes.</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Demasiado muchas operaciones LDAP.</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>Licencia no correcta</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>Licencia ha expirado</value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>Número de portales excede el número permitido por la licencia</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>Número de usuarios excede el número permitido por la licencia</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Subido con éxito</value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Se ha subido correctamente. {0}Soporte y atualizaciones no están disponibles para esta licencia desde {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>Las instrucciones para cambiar el correo electrónico se han enviado con éxito</value>
|
||||
</data>
|
||||
@ -234,6 +220,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Cuota de espacio en disco excedida </value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Acceso a portal</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Perfil ha sido eliminado</value>
|
||||
</data>
|
||||
|
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Notifications d'administrateurs</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Votre message a été envoyé avec succès. Vous serez contacté par l'administrateur du portail.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un lien pour confirmer l'opération a été envoyé à :e-mail (l'adresse e-mail du propriétaire du portail).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Personnel</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Adresse e-mail incorrecte</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Le code promo est incorrect </value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>Ces paramètres ont été bien enregistrés</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>Pas d'autorisation pour effectuer cette action</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>{!User} avec la même adresse e-mail est déjà inscrit</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>Adresses provenant de ce domaine ne sont pas acceptées pour l'enregistrement</value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Le champ Email est vide</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>L'adresse email actuelle et la nouvelle adresse sont les mêmes</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Texte du message est vide</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>Le fichier chargé ne peut pas être trouvé</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>Adresse email non valide</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Nom de domaine non valide</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>Le champ "Mot de passe" est vide.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>lettres majuscules</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Le délai de requête est dépassé</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>Il est impossible de trouver l'utilisateur</value>
|
||||
</data>
|
||||
@ -215,12 +180,33 @@
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>Le lien pour confirmer votre compte a été envoyé à l'adresse email indiquée</value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>Le serveur n'a pas pu enregistrer des paramètres.</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Trop d'opérations LDAP.</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>La licence n'est pas correcte</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>La licence a expiré</value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>Le nombre de portails a dépassé la limite autorisée par la licence</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>Le nombre d'utilisateurs a dépassé la limite autorisée par la licence</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Téléchargé avec succès</value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Téléchargé avec succès. {0}Support et mises à jour ne sont plus disponibles pour cette licence depuis {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>Les instructions de changement d'émail ont été envoyées avec succès</value>
|
||||
</data>
|
||||
@ -236,6 +222,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Quota d'espace disque est dépassé</value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Accès au portail</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Le profil a été supprimé</value>
|
||||
</data>
|
||||
|
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Notifiche di amministratore</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Il tuo messaggio è stato inviato con successo. Sarai contattato dall'amministratore del portale.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un collegamento per confermare l'operazione è stato inviato all'indirizzo :email (l'indirizzo email del proprietario del portale).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Personalizzato</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Indirizzo email non corretto</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Codice promozionale errato</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>Queste impostazioni sono state salvate con successo</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>Non si dispone di permessi sufficienti per effettuare questa azione</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>Un {!user} con questo indirizzo email è già registrato</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>Impossibile usare gli indirizzi email da questo dominio per iscrizione</value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Il campo Email è vuoto</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>L'indirizzo email corrente coincide con quello nuovo.</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Il testo del messaggio è vuoto</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>E' impossibile trovare il file caricato</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>Indirizzo email non valido</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Nome dominio non valido</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>Il campo Password è vuoto.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>lettere maiuscole</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Il limite di richieste è stato superato</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>L'utente non è stato trovato</value>
|
||||
</data>
|
||||
@ -213,12 +178,33 @@
|
||||
<data name="FileSizePostfix" xml:space="preserve">
|
||||
<value>byte,KB,MB,GB,TB</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>Il collegamento per confermare il tuo account è stato inviato all'indirizzo email specificato</value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>Il server non è riuscito a salvare le impostazioni.</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Troppe operazioni LDAP</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>Licenza errata</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>La licenza è scaduta</value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>Il numero di portali supera quello consentito dalla licenza</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>Il numero di utenti supera quello consentito dalla licenza</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Caricato con successo</value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Caricato con successo. {0}Il supporto e gli aggiornamenti non sono disponibili per questa licenza dal {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>Le istruzioni di modifica dell'email sono state inviate correttamente</value>
|
||||
</data>
|
||||
@ -234,6 +220,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Quota di spazio su disco superata</value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Accesso al portale</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Il profilo è stato eliminato</value>
|
||||
</data>
|
||||
|
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Administrator Notifications</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Your message was successfully sent. You will be contacted by the portal administrator.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>A link to confirm the operation has been sent to :email (the email address of the portal owner).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Custom</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Incorrect email address</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Incorrect promo code</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>These settings have been successfully saved</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>No permissions to perform this action</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>{!User} with this email is already registered</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>Emails from this domain are not allowed for registration</value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Email field is empty</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>The current email and the new email are the same</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Message text is empty</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>The uploaded file could not be found</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>Incorrect email</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Invalid domain name</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>The password is empty.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>capital letters</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Request limit is exceeded</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>The user could not be found</value>
|
||||
</data>
|
||||
@ -213,12 +178,33 @@
|
||||
<data name="FileSizePostfix" xml:space="preserve">
|
||||
<value>bytes,KB,MB,GB,TB</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>The link to confirm your account has been sent to the specified email</value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>The server could not save settings.</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Too many LDAP operations.</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>License is not correct</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>License has expired</value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>The number of portals exceeds the one allowed by the license</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>The number of users exceeds the one allowed by the license</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Uploaded successfully</value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Uploaded successfully. {0}Support and updates are not available for this license since {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>The email change instructions have been successfuly sent</value>
|
||||
</data>
|
||||
@ -234,6 +220,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Disk space quota exceeded</value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Portal Access</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Profile has been removed</value>
|
||||
</data>
|
||||
|
@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@ -129,6 +70,9 @@
|
||||
<data name="AdministratorNotifySenderTypeName" xml:space="preserve">
|
||||
<value>Извещения администраторов</value>
|
||||
</data>
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Ваше сообщение успешно отправлено. Администратор портала с Вами свяжется.</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Ссылка для подтверждения операции была отправлена на :email (адрес электронной почты владельца портала).</value>
|
||||
</data>
|
||||
@ -141,6 +85,15 @@
|
||||
<data name="CustomNamingPeopleSchema" xml:space="preserve">
|
||||
<value>Пользовательский</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectEmail" xml:space="preserve">
|
||||
<value>Некорректный адрес электронной почты</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordIncorrectPromocode" xml:space="preserve">
|
||||
<value>Неверный промо-код</value>
|
||||
</data>
|
||||
<data name="EmailAndPasswordSaved" xml:space="preserve">
|
||||
<value>Эти параметры были успешно сохранены</value>
|
||||
</data>
|
||||
<data name="ErrorAccessDenied" xml:space="preserve">
|
||||
<value>Недостаточно прав для выполнения данной операции</value>
|
||||
</data>
|
||||
@ -153,12 +106,18 @@
|
||||
<data name="ErrorEmailAlreadyExists" xml:space="preserve">
|
||||
<value>{!User} с таким адресом email уже зарегистрирован</value>
|
||||
</data>
|
||||
<data name="ErrorEmailDomainNotAllowed" xml:space="preserve">
|
||||
<value>Адреса с этого домена не разрешены для регистрации</value>
|
||||
</data>
|
||||
<data name="ErrorEmailEmpty" xml:space="preserve">
|
||||
<value>Не заполнено поле адреса электронной почты</value>
|
||||
</data>
|
||||
<data name="ErrorEmailsAreTheSame" xml:space="preserve">
|
||||
<value>Текущий адрес электронной почты совпадает с новым адресом</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyMessage" xml:space="preserve">
|
||||
<value>Отсутствует текст сообщения</value>
|
||||
</data>
|
||||
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
|
||||
<value>Загружаемый файл не найден</value>
|
||||
</data>
|
||||
@ -174,6 +133,9 @@
|
||||
<data name="ErrorNotCorrectEmail" xml:space="preserve">
|
||||
<value>Неправильный email</value>
|
||||
</data>
|
||||
<data name="ErrorNotCorrectTrustedDomain" xml:space="preserve">
|
||||
<value>Неправильное имя домена</value>
|
||||
</data>
|
||||
<data name="ErrorPasswordEmpty" xml:space="preserve">
|
||||
<value>Поле Пароль не заполнено.</value>
|
||||
</data>
|
||||
@ -195,6 +157,9 @@
|
||||
<data name="ErrorPasswordNoUpperCase" xml:space="preserve">
|
||||
<value>заглавные буквы</value>
|
||||
</data>
|
||||
<data name="ErrorRequestLimitExceeded" xml:space="preserve">
|
||||
<value>Превышен лимит запросов</value>
|
||||
</data>
|
||||
<data name="ErrorUserNotFound" xml:space="preserve">
|
||||
<value>Пользователь не найден</value>
|
||||
</data>
|
||||
@ -213,12 +178,33 @@
|
||||
<data name="FileSizePostfix" xml:space="preserve">
|
||||
<value>байт,Кб,Мб,Гб,Тб</value>
|
||||
</data>
|
||||
<data name="FinishInviteJoinEmailMessage" xml:space="preserve">
|
||||
<value>На указанный email была выслана ссылка для подтверждения новой учетной записи</value>
|
||||
</data>
|
||||
<data name="LdapSettingsErrorCantSaveLdapSettings" xml:space="preserve">
|
||||
<value>Серверу не удалось сохранить настройки.</value>
|
||||
</data>
|
||||
<data name="LdapSettingsTooManyOperations" xml:space="preserve">
|
||||
<value>Слишком много операций LDAP.</value>
|
||||
</data>
|
||||
<data name="LicenseError" xml:space="preserve">
|
||||
<value>Некорректная лицензия</value>
|
||||
</data>
|
||||
<data name="LicenseErrorExpired" xml:space="preserve">
|
||||
<value>Истек срок действия лицензии</value>
|
||||
</data>
|
||||
<data name="LicenseErrorPortal" xml:space="preserve">
|
||||
<value>Превышено количество порталов, разрешенных по лицензии</value>
|
||||
</data>
|
||||
<data name="LicenseErrorQuota" xml:space="preserve">
|
||||
<value>Превышено количество пользователей, разрешенных по лицензии</value>
|
||||
</data>
|
||||
<data name="LicenseUploaded" xml:space="preserve">
|
||||
<value>Успешно загружено</value>
|
||||
</data>
|
||||
<data name="LicenseUploadedOverdue" xml:space="preserve">
|
||||
<value>Успешно загружено. {0}Поддержка и обновления недоступны для этой лицензии с {2}.{1}</value>
|
||||
</data>
|
||||
<data name="MessageEmailChangeInstuctionsSentOnEmail" xml:space="preserve">
|
||||
<value>Инструкции по изменению электронной почты были успешно отправлены</value>
|
||||
</data>
|
||||
@ -234,6 +220,9 @@
|
||||
<data name="PersonalFreeSpaceException" xml:space="preserve">
|
||||
<value>Превышена квота на размер дискового пространства</value>
|
||||
</data>
|
||||
<data name="PortalSecurity" xml:space="preserve">
|
||||
<value>Доступ к порталу</value>
|
||||
</data>
|
||||
<data name="ProfileRemoved" xml:space="preserve">
|
||||
<value>Профиль удален</value>
|
||||
</data>
|
||||
|
@ -69,6 +69,33 @@ namespace ASC.Web.Core.PublicResources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to License expired or user quota does not match the license.
|
||||
/// </summary>
|
||||
public static string LicenseException {
|
||||
get {
|
||||
return ResourceManager.GetString("LicenseException", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to License key is not correct.
|
||||
/// </summary>
|
||||
public static string LicenseKeyNotCorrect {
|
||||
get {
|
||||
return ResourceManager.GetString("LicenseKeyNotCorrect", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You must enter a license key.
|
||||
/// </summary>
|
||||
public static string LicenseKeyNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("LicenseKeyNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to month.
|
||||
/// </summary>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>Die Backup-Funktion ist nicht verfügbar, weil der Speicherplatz überschreitet {0}. Gehen Sie zum {1}Abschnitt "Statistik"{2} um besetzten Speicherplatz zu überprüfen.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>Lizenz ist abgelaufen oder Benutzer-Quote zusammenfällt die Lizenz nicht.</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>Lizenzschlüssel ist nicht korrekt</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>Sie müssen Lizenzschlüssel einsetzen</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>Monat</value>
|
||||
</data>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>La función de Backup no está disponible porque el espacio de almacenamiento excede {0}. Pase a la sección {1}Estadística{2} para obtener información sobre espacio usado.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>Licencia ha caducado o cuota de los usuarios no coincide con la licencia</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>La clave de la licencia no es correcta</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>Tiene que meter la clave de la licencia</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>mes</value>
|
||||
</data>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>La fonction de sauvegarde n'est pas disponible car l'espace de stockage dépasse {0}. Passez à la section {1}Statistique{2} pour vérifier l'espace de stockage utilisé.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>La licence expirée ou le quota de l'utilisateur ne correspond pas à la licence</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>Clé de licence est pas correcte</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>Vous devez entrer une clé de licence</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>mois</value>
|
||||
</data>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>La funzione di backup non è disponibile, siccome lo spazio di archiviazione supera {0}. Vai alla {1}sezione Statistiche{2} per verificare lo spazio di archiviazione utilizzato.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>Licenza è scaduta oppure il numero di utenti non corrisponde alla licenza</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>La chiave della licenza non è corretta</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>Devi inserire una chiave di licenza</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>mese</value>
|
||||
</data>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>The Backup function is not available as the storage space exceeds {0}. Go to the {1}Statistics section{2} to check the storage space used.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>License expired or user quota does not match the license</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>License key is not correct</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>You must enter a license key</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>month</value>
|
||||
</data>
|
||||
|
@ -61,6 +61,15 @@
|
||||
<data name="BackupSpaceExceed" xml:space="preserve">
|
||||
<value>Функция резервного копирования недоступна, так как дисковое пространство превышает {0}. Перейдите в {1}раздел "Статистика"{2}, чтобы проверить занятое дисковое пространство.</value>
|
||||
</data>
|
||||
<data name="LicenseException" xml:space="preserve">
|
||||
<value>Истек срок действия лицензии или количество пользователей не соответствует лицензии</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotCorrect" xml:space="preserve">
|
||||
<value>Некорректный лицензионный ключ</value>
|
||||
</data>
|
||||
<data name="LicenseKeyNotFound" xml:space="preserve">
|
||||
<value>Необходимо ввести лицензионный ключ</value>
|
||||
</data>
|
||||
<data name="TariffPerMonth" xml:space="preserve">
|
||||
<value>месяц</value>
|
||||
</data>
|
||||
|
@ -178,7 +178,7 @@ namespace ASC.Web.Studio.Core
|
||||
DisplayPersonalBanners = GetAppSettings("web.display.personal.banners", false);
|
||||
ShareTwitterUrl = GetAppSettings("web.share.twitter", "https://twitter.com/intent/tweet?text={0}");
|
||||
ShareFacebookUrl = GetAppSettings("web.share.facebook", "");
|
||||
ControlPanelUrl = GetAppSettings("web.controlpanel.url", "");
|
||||
ControlPanelUrl = GetAppSettings("web:controlpanel:url", "");
|
||||
FontOpenSansUrl = GetAppSettings("web.font.opensans.url", "");
|
||||
VoipEnabled = GetAppSettings("voip.enabled", "false");
|
||||
StartProductList = GetAppSettings("web.start.product.list", "");
|
||||
|
@ -25,8 +25,9 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using ASC.Core.Common.Settings;
|
||||
|
||||
namespace ASC.Web.Studio.UserControls.Management
|
||||
@ -34,17 +35,17 @@ namespace ASC.Web.Studio.UserControls.Management
|
||||
[Serializable]
|
||||
public class TariffSettings : ISettings
|
||||
{
|
||||
private static readonly CultureInfo CultureInfo = CultureInfo.CreateSpecificCulture("en-US");
|
||||
|
||||
private static readonly CultureInfo CultureInfo = CultureInfo.CreateSpecificCulture("en-US");
|
||||
|
||||
[JsonPropertyName("HideRecommendation")]
|
||||
public bool HideBuyRecommendationSetting { get; set; }
|
||||
|
||||
public bool HideBuyRecommendationSetting { get; set; }
|
||||
|
||||
[JsonPropertyName("HideNotify")]
|
||||
public bool HideNotifySetting { get; set; }
|
||||
|
||||
public bool HideNotifySetting { get; set; }
|
||||
|
||||
[JsonPropertyName("HidePricingPage")]
|
||||
public bool HidePricingPageForUsers { get; set; }
|
||||
|
||||
public bool HidePricingPageForUsers { get; set; }
|
||||
|
||||
[JsonPropertyName("LicenseAccept")]
|
||||
public string LicenseAcceptSetting { get; set; }
|
||||
|
||||
@ -65,54 +66,55 @@ namespace ASC.Web.Studio.UserControls.Management
|
||||
}
|
||||
|
||||
//TODO: Need to be returned when needed
|
||||
//public bool HideRecommendation
|
||||
//{
|
||||
// get { return LoadForCurrentUser().HideBuyRecommendationSetting; }
|
||||
// set
|
||||
// {
|
||||
// var tariffSettings = LoadForCurrentUser();
|
||||
// tariffSettings.HideBuyRecommendationSetting = value;
|
||||
// tariffSettings.SaveForCurrentUser();
|
||||
// }
|
||||
//}
|
||||
public static bool GetHideRecommendation(SettingsManager settingsManager)
|
||||
{
|
||||
return settingsManager.LoadForCurrentUser<TariffSettings>().HideBuyRecommendationSetting;
|
||||
}
|
||||
|
||||
public static void SetHideRecommendation(SettingsManager settingsManager, bool newVal)
|
||||
{
|
||||
var tariffSettings = settingsManager.LoadForCurrentUser<TariffSettings>();
|
||||
tariffSettings.HideBuyRecommendationSetting = newVal;
|
||||
settingsManager.SaveForCurrentUser(tariffSettings);
|
||||
}
|
||||
|
||||
public static bool GetHideNotify(SettingsManager settingsManager)
|
||||
{
|
||||
return settingsManager.LoadForCurrentUser<TariffSettings>().HideNotifySetting;
|
||||
}
|
||||
|
||||
public static void SetHideNotify(SettingsManager settingsManager, bool newVal)
|
||||
{
|
||||
var tariffSettings = settingsManager.LoadForCurrentUser<TariffSettings>();
|
||||
tariffSettings.HideNotifySetting = newVal;
|
||||
settingsManager.SaveForCurrentUser(tariffSettings);
|
||||
}
|
||||
|
||||
//public bool HideNotify
|
||||
//{
|
||||
// get { return LoadForCurrentUser().HideNotifySetting; }
|
||||
// set
|
||||
// {
|
||||
// var tariffSettings = LoadForCurrentUser();
|
||||
// tariffSettings.HideNotifySetting = value;
|
||||
// tariffSettings.SaveForCurrentUser();
|
||||
// }
|
||||
//}
|
||||
public static bool GetHidePricingPage(SettingsManager settingsManager)
|
||||
{
|
||||
return settingsManager.Load<TariffSettings>().HidePricingPageForUsers;
|
||||
}
|
||||
|
||||
//public bool HidePricingPage
|
||||
//{
|
||||
// get { return Load().HidePricingPageForUsers; }
|
||||
// set
|
||||
// {
|
||||
// var tariffSettings = Load();
|
||||
// tariffSettings.HidePricingPageForUsers = value;
|
||||
// tariffSettings.Save();
|
||||
// }
|
||||
//}
|
||||
public static void SetHidePricingPage(SettingsManager settingsManager, bool newVal)
|
||||
{
|
||||
var tariffSettings = settingsManager.Load<TariffSettings>();
|
||||
tariffSettings.HidePricingPageForUsers = newVal;
|
||||
settingsManager.Save<TariffSettings>(tariffSettings);
|
||||
}
|
||||
|
||||
//public bool LicenseAccept
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return !DateTime.MinValue.ToString(CultureInfo).Equals(LoadForDefaultTenant().LicenseAcceptSetting);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// var tariffSettings = LoadForDefaultTenant();
|
||||
// if (DateTime.MinValue.ToString(CultureInfo).Equals(tariffSettings.LicenseAcceptSetting))
|
||||
// {
|
||||
// tariffSettings.LicenseAcceptSetting = DateTime.UtcNow.ToString(CultureInfo);
|
||||
// tariffSettings.SaveForDefaultTenant();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
public static bool GetLicenseAccept(SettingsManager settingsManager)
|
||||
{
|
||||
return !DateTime.MinValue.ToString(CultureInfo).Equals(settingsManager.LoadForDefaultTenant<TariffSettings>().LicenseAcceptSetting);
|
||||
}
|
||||
|
||||
public static void SetLicenseAccept(SettingsManager settingsManager)
|
||||
{
|
||||
var tariffSettings = settingsManager.LoadForDefaultTenant<TariffSettings>();
|
||||
if (DateTime.MinValue.ToString(CultureInfo).Equals(tariffSettings.LicenseAcceptSetting))
|
||||
{
|
||||
tariffSettings.LicenseAcceptSetting = DateTime.UtcNow.ToString(CultureInfo);
|
||||
settingsManager.SaveForDefaultTenant(tariffSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -521,10 +521,15 @@ namespace ASC.Web.Studio.Utility
|
||||
}
|
||||
|
||||
public string GetConfirmationUrlRelative(string email, ConfirmType confirmType, object postfix = null, Guid userId = default)
|
||||
{
|
||||
return $"confirm/{confirmType}?{GetToken(email, confirmType, postfix, userId)}";
|
||||
}
|
||||
|
||||
public string GetToken(string email, ConfirmType confirmType, object postfix = null, Guid userId = default)
|
||||
{
|
||||
var validationKey = EmailValidationKeyProvider.GetEmailKey(email + confirmType + (postfix ?? ""));
|
||||
|
||||
var link = $"confirm/{confirmType}?key={validationKey}";
|
||||
var link = $"type={confirmType}&key={validationKey}";
|
||||
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user