Merge branch 'hotfix/v1.0.1' into feature/files-upload

This commit is contained in:
Nikita Gopienko 2021-11-01 14:08:44 +03:00
commit e6628c4963
21 changed files with 106 additions and 91 deletions

View File

@ -11,15 +11,16 @@ namespace ASC.Api.Core
{
public class BaseWorkerStartup
{
public IConfiguration Configuration { get; }
public IConfiguration Configuration { get; }
public BaseWorkerStartup(IConfiguration configuration)
{
Configuration = configuration;
}
public virtual void ConfigureServices(IServiceCollection services)
{
{
services.AddHttpContextAccessor();
services.AddCustomHealthCheck(Configuration);
}

View File

@ -36,6 +36,7 @@ using System.Threading.Tasks;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.EF;
using ASC.Core.Common.EF.Context;
@ -102,14 +103,14 @@ namespace ASC.ElasticSearch
DbContextManager<WebstudioDbContext> dbContextManager,
TenantManager tenantManager,
BaseIndexerHelper baseIndexerHelper,
Settings settings,
ConfigurationExtension configurationExtension,
IServiceProvider serviceProvider)
{
Client = client;
Log = log.CurrentValue;
TenantManager = tenantManager;
BaseIndexerHelper = baseIndexerHelper;
Settings = settings;
Settings = Settings.GetInstance(configurationExtension);
ServiceProvider = serviceProvider;
LazyWebstudioDbContext = new Lazy<WebstudioDbContext>(() => dbContextManager.Value);
}

View File

@ -29,6 +29,7 @@ using System.Text;
using ASC.Common;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch.Service;
@ -53,11 +54,11 @@ namespace ASC.ElasticSearch
private CoreConfiguration CoreConfiguration { get; }
private Settings Settings { get; }
public Client(IOptionsMonitor<ILog> option, CoreConfiguration coreConfiguration, Settings settings)
public Client(IOptionsMonitor<ILog> option, CoreConfiguration coreConfiguration, ConfigurationExtension configurationExtension)
{
Log = option.Get("ASC.Indexer");
CoreConfiguration = coreConfiguration;
Settings = settings;
Settings = Settings.GetInstance(configurationExtension);
}
public ElasticClient Instance

View File

@ -32,6 +32,7 @@ using System.Threading.Tasks;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.ElasticSearch.Service;
using Microsoft.Extensions.DependencyInjection;
@ -57,13 +58,14 @@ namespace ASC.ElasticSearch
ICacheNotify<AscCacheItem> notify,
ICacheNotify<IndexAction> indexNotify,
IServiceProvider serviceProvider,
Settings settings)
ConfigurationExtension configurationExtension)
{
Log = options.Get("ASC.Indexer");
Notify = notify;
IndexNotify = indexNotify;
ServiceProvider = serviceProvider;
CancellationTokenSource = new CancellationTokenSource();
var settings = Settings.GetInstance(configurationExtension);
Period = TimeSpan.FromMinutes(settings.Period.Value);
}

View File

@ -31,24 +31,21 @@ namespace ASC.ElasticSearch.Service
{
[Singletone]
public class Settings
{
public Settings()
{
public static Settings GetInstance(ConfigurationExtension configuration)
{
}
public Settings(ConfigurationExtension configuration)
{
var result = new Settings();
var cfg = configuration.GetSetting<Settings>("elastic");
Scheme = cfg.Scheme ?? "http";
Host = cfg.Host ?? "localhost";
Port = cfg.Port ?? 9200;
Period = cfg.Period ?? 1;
MaxContentLength = cfg.MaxContentLength ?? 100 * 1024 * 1024L;
MaxFileSize = cfg.MaxFileSize ?? 10 * 1024 * 1024L;
Threads = cfg.Threads ?? 1;
HttpCompression = cfg.HttpCompression ?? true;
}
result.Scheme = cfg.Scheme ?? "http";
result.Host = cfg.Host ?? "localhost";
result.Port = cfg.Port ?? 9200;
result.Period = cfg.Period ?? 1;
result.MaxContentLength = cfg.MaxContentLength ?? 100 * 1024 * 1024L;
result.MaxFileSize = cfg.MaxFileSize ?? 10 * 1024 * 1024L;
result.Threads = cfg.Threads ?? 1;
result.HttpCompression = cfg.HttpCompression ?? true;
return result;
}
public string Host { get; set; }

View File

@ -7,7 +7,7 @@ import Text from "../text";
import Loaders from "@appserver/common/components/Loaders";
const onButtonClick = (url) => {
window.location = url;
window.open(url, "_blank");
};
const CampaignsBanner = (props) => {

View File

@ -156,7 +156,8 @@ const EditingWrapperComponent = (props) => {
const onFocus = (e) => e.target.select();
const onBlur = (e) => {
if (e.relatedTarget.classList.contains("edit-button")) return false;
if (e.relatedTarget && e.relatedTarget.classList.contains("edit-button"))
return false;
onClickUpdateItem(e, false);
};
@ -171,7 +172,7 @@ const EditingWrapperComponent = (props) => {
tabIndex={1}
isAutoFocussed={true}
onChange={renameTitle}
onKeyUp={onKeyUpUpdateItem}
onKeyPress={onKeyUpUpdateItem}
onKeyDown={onEscapeKeyPress}
onFocus={onFocus}
onBlur={onBlur}

View File

@ -93,7 +93,7 @@ const FileRow = (props) => {
setMediaViewerData,
setUploadPanelVisible,
isMediaActive,
isArchive,
downloadInCurrentTab,
} = props;
const onCancelCurrentUpload = (e) => {
@ -116,7 +116,6 @@ const FileRow = (props) => {
? { onClick: onCancelCurrentUpload }
: {};
const downloadInCurrentTab = isArchive(ext);
return (
<>
<StyledFileRow
@ -239,7 +238,12 @@ export default inject(
}
const { personal } = auth.settingsStore;
const { iconFormatsStore, mediaViewersFormatsStore } = formatsStore;
const {
iconFormatsStore,
mediaViewersFormatsStore,
docserviceStore,
} = formatsStore;
const { canViewedDocs } = docserviceStore;
const {
uploaded,
primaryProgressDataStore,
@ -263,6 +267,9 @@ export default inject(
: null;
const { isArchive } = iconFormatsStore;
const downloadInCurrentTab = isArchive(ext) || !canViewedDocs(ext);
return {
isPersonal: personal,
currentFileUploadProgress,
@ -273,12 +280,12 @@ export default inject(
name,
loadingFile,
isMediaActive,
downloadInCurrentTab,
cancelCurrentUpload,
cancelCurrentFileConversion,
setMediaViewerData,
setUploadPanelVisible,
isArchive,
};
}
)(withTranslation("UploadPanel")(observer(FileRow)));

View File

@ -295,7 +295,7 @@ class SectionHeaderContent extends React.Component {
onBackToParentFolder = () => {
const { setIsLoading, parentId, filter, fetchFiles } = this.props;
setIsLoading(true);
fetchFiles(parentId, filter).finally(() => setIsLoading(false));
fetchFiles(parentId, null, true, false).finally(() => setIsLoading(false));
};
onCheck = (checked) => {

View File

@ -98,7 +98,7 @@ class FilesStore {
};
setStartDrag = (startDrag) => {
this.selection = this.selection.filter((x) => !x.isThirdPartyFolder); // removed root thirdparty folders
this.selection = this.selection.filter((x) => !x.providerKey); // removed root thirdparty folders
this.startDrag = startDrag;
};

View File

@ -34,6 +34,7 @@ using System.Threading.Tasks;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.EF;
using ASC.Core.Common.Settings;
@ -97,7 +98,7 @@ namespace ASC.Files.Core.Data
ChunkedUploadSessionHolder chunkedUploadSessionHolder,
ProviderFolderDao providerFolderDao,
CrossDao crossDao,
Settings settings)
ConfigurationExtension configurationExtension)
: base(
dbContextManager,
userManager,
@ -122,7 +123,7 @@ namespace ASC.Files.Core.Data
ChunkedUploadSessionHolder = chunkedUploadSessionHolder;
ProviderFolderDao = providerFolderDao;
CrossDao = crossDao;
Settings = settings;
Settings = Settings.GetInstance(configurationExtension);
}
public void InvalidateCache(int fileId)

View File

@ -31,6 +31,7 @@ using System.Threading.Tasks;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.EF.Model;
using ASC.ElasticSearch;
@ -48,7 +49,7 @@ namespace ASC.Web.Files.Core.Search
public class FactoryIndexerFile : FactoryIndexer<DbFile>
{
private IDaoFactory DaoFactory { get; }
public Settings Settings { get; }
private Settings Settings { get; }
public FactoryIndexerFile(
IOptionsMonitor<ILog> options,
@ -59,11 +60,11 @@ namespace ASC.Web.Files.Core.Search
IServiceProvider serviceProvider,
IDaoFactory daoFactory,
ICache cache,
Settings settings)
ConfigurationExtension configurationExtension)
: base(options, tenantManager, searchSettingsHelper, factoryIndexer, baseIndexer, serviceProvider, cache)
{
DaoFactory = daoFactory;
Settings = settings;
Settings = Settings.GetInstance(configurationExtension);
}
public override void IndexAll()
@ -73,18 +74,22 @@ namespace ASC.Web.Files.Core.Search
(int, int, int) getCount(DateTime lastIndexed)
{
var dataQuery = GetBaseQuery(lastIndexed)
.Where(r => r.DbFile.Version == 1)
.OrderBy(r => r.DbFile.Id)
.Select(r => r.DbFile.Id);
var minid = dataQuery.FirstOrDefault();
dataQuery = GetBaseQuery(lastIndexed)
.Where(r => r.DbFile.Version == 1)
.OrderByDescending(r => r.DbFile.Id)
.Select(r => r.DbFile.Id);
var maxid = dataQuery.FirstOrDefault();
var count = GetBaseQuery(lastIndexed).Count();
var count = GetBaseQuery(lastIndexed)
.Where(r => r.DbFile.Version == 1)
.Count();
return new(count, maxid, minid);
}
@ -92,7 +97,7 @@ namespace ASC.Web.Files.Core.Search
List<DbFile> getData(long start, long stop, DateTime lastIndexed)
{
return GetBaseQuery(lastIndexed)
.Where(r => r.DbFile.Id >= start && r.DbFile.Id <= stop)
.Where(r => r.DbFile.Id >= start && r.DbFile.Id <= stop && r.DbFile.CurrentVersion)
.Select(r => r.DbFile)
.ToList();
@ -106,6 +111,7 @@ namespace ASC.Web.Files.Core.Search
{
var dataQuery = GetBaseQuery(lastIndexed)
.Where(r => r.DbFile.Id >= start)
.Where(r => r.DbFile.Version == 1)
.OrderBy(r => r.DbFile.Id)
.Select(r => r.DbFile.Id)
.Skip(BaseIndexer<DbFile>.QueryLimit);
@ -127,7 +133,6 @@ namespace ASC.Web.Files.Core.Search
IQueryable<FileTenant> GetBaseQuery(DateTime lastIndexed) => fileDao.FilesDbContext.Files
.Where(r => r.ModifiedOn >= lastIndexed)
.Where(r => r.CurrentVersion)
.Join(fileDao.FilesDbContext.Tenants, r => r.TenantId, r => r.Id, (f, t) => new FileTenant { DbFile = f, DbTenant = t })
.Where(r => r.DbTenant.Status == ASC.Core.Tenants.TenantStatus.Active);

View File

@ -32,6 +32,7 @@ using System.Threading.Tasks;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.EF.Model;
using ASC.ElasticSearch;
@ -49,7 +50,7 @@ namespace ASC.Web.Files.Core.Search
public class FactoryIndexerFolder : FactoryIndexer<DbFolder>
{
private IDaoFactory DaoFactory { get; }
public Settings Settings { get; }
private Settings Settings { get; }
public FactoryIndexerFolder(
IOptionsMonitor<ILog> options,
@ -60,11 +61,11 @@ namespace ASC.Web.Files.Core.Search
IServiceProvider serviceProvider,
IDaoFactory daoFactory,
ICache cache,
Settings settings)
ConfigurationExtension configurationExtension)
: base(options, tenantManager, searchSettingsHelper, factoryIndexer, baseIndexer, serviceProvider, cache)
{
DaoFactory = daoFactory;
Settings = settings;
Settings = Settings.GetInstance(configurationExtension);
}
public override void IndexAll()

View File

@ -695,7 +695,7 @@ namespace ASC.Web.Files.Utils
if (filter != FilterType.FoldersOnly)
{
files = fileDao.GetFilesFiltered(fileIds, filter, subjectGroup, subjectId, searchText, searchInContent);
files = fileDao.GetFilesFiltered(fileIds, filter, subjectGroup, subjectId, searchText, searchInContent, true);
files = files.Where(file => file.RootFolderType != FolderType.TRASH).ToList();
files = fileSecurity.FilterRead(files).ToList();

View File

@ -48,11 +48,11 @@ namespace ASC.Files.ThumbnailBuilder
private readonly ILog logger;
private IServiceProvider ServiceProvider { get; }
public BuilderQueue(IServiceProvider serviceProvider, IOptionsMonitor<ILog> log, ThumbnailSettings thumbnailSettings)
public BuilderQueue(IServiceProvider serviceProvider, IOptionsMonitor<ILog> log, ASC.Common.Utils.ConfigurationExtension configurationExtension)
{
logger = log.Get("ASC.Files.ThumbnailBuilder");
ServiceProvider = serviceProvider;
config = thumbnailSettings;
config = ThumbnailSettings.GetInstance(configurationExtension);
}
public void BuildThumbnails(IEnumerable<FileData<T>> filesWithoutThumbnails)
@ -62,13 +62,14 @@ namespace ASC.Files.ThumbnailBuilder
Parallel.ForEach(
filesWithoutThumbnails,
new ParallelOptions { MaxDegreeOfParallelism = config.MaxDegreeOfParallelism },
(fileData) => {
(fileData) =>
{
using var scope = ServiceProvider.CreateScope();
var commonLinkUtilitySettings = scope.ServiceProvider.GetService<CommonLinkUtilitySettings>();
commonLinkUtilitySettings.ServerUri = fileData.BaseUri;
var builder = scope.ServiceProvider.GetService<Builder<T>>();
builder.BuildThumbnail(fileData);
builder.BuildThumbnail(fileData);
}
);
}
@ -93,7 +94,7 @@ namespace ASC.Files.ThumbnailBuilder
private PathProvider PathProvider { get; }
public Builder(
ThumbnailSettings config,
Common.Utils.ConfigurationExtension configurationExtension,
TenantManager tenantManager,
IDaoFactory daoFactory,
DocumentServiceConnector documentServiceConnector,
@ -102,7 +103,7 @@ namespace ASC.Files.ThumbnailBuilder
PathProvider pathProvider,
IOptionsMonitor<ILog> log)
{
this.config = config;
this.config = ThumbnailSettings.GetInstance(configurationExtension);
TenantManager = tenantManager;
DaoFactory = daoFactory;
DocumentServiceConnector = documentServiceConnector;

View File

@ -42,13 +42,13 @@ namespace ASC.Files.ThumbnailBuilder
private readonly string cacheKey;
public FileDataProvider(
ThumbnailSettings thumbnailSettings,
Common.Utils.ConfigurationExtension configurationExtension,
ICache ascCache,
DbContextManager<FilesDbContext> dbContextManager,
DbContextManager<CoreDbContext> coredbContextManager
)
{
this.thumbnailSettings = thumbnailSettings;
thumbnailSettings = ThumbnailSettings.GetInstance(configurationExtension);
cache = ascCache;
LazyFilesDbContext = new Lazy<FilesDbContext>(() => dbContextManager.Get(thumbnailSettings.ConnectionStringName));
LazyCoreDbContext = new Lazy<CoreDbContext>(() => coredbContextManager.Get(thumbnailSettings.ConnectionStringName));
@ -112,13 +112,13 @@ namespace ASC.Files.ThumbnailBuilder
)
.GroupBy(r => r.tariff.Tenant)
.Select(r => new { tenant = r.Key, stamp = r.Max(b => b.tariff.Stamp) })
.Where(r=> r.stamp > DateTime.UtcNow);
result = search.Select(r=> r.tenant).ToArray();
cache.Insert(cacheKey, result, DateTime.UtcNow.AddHours(1));
return result;
.Where(r => r.stamp > DateTime.UtcNow);
result = search.Select(r => r.tenant).ToArray();
cache.Insert(cacheKey, result, DateTime.UtcNow.AddHours(1));
return result;
}
private IEnumerable<FileData<int>> GetFileData(Expression<Func<DbFile, bool>> where)

View File

@ -25,25 +25,22 @@ namespace ASC.Files.ThumbnailBuilder
[Singletone]
public class ThumbnailSettings
{
public ThumbnailSettings()
{
}
public ThumbnailSettings(ConfigurationExtension configuration)
public static ThumbnailSettings GetInstance(ConfigurationExtension configuration)
{
var result = new ThumbnailSettings();
var cfg = configuration.GetSetting<ThumbnailSettings>("thumbnail");
ServerRoot = cfg.ServerRoot ?? "http://localhost/";
LaunchFrequency = cfg.LaunchFrequency != 0 ? cfg.LaunchFrequency : 1;
ConnectionStringName = cfg.ConnectionStringName ?? "default";
Formats = cfg.Formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico";
SqlMaxResults = cfg.SqlMaxResults != 0 ? cfg.SqlMaxResults : 1000;
MaxDegreeOfParallelism = cfg.MaxDegreeOfParallelism != 0 ? cfg.MaxDegreeOfParallelism : 10;
AvailableFileSize = cfg.AvailableFileSize ?? 100L * 1024L * 1024L;
AttemptsLimit = cfg.AttemptsLimit ?? 3;
AttemptWaitInterval = cfg.AttemptWaitInterval != 0 ? cfg.AttemptWaitInterval : 1000;
ThumbnaillHeight = cfg.ThumbnaillHeight != 0 ? cfg.ThumbnaillHeight : 128;
ThumbnaillWidth = cfg.ThumbnaillWidth != 0 ? cfg.ThumbnaillWidth : 192;
result.ServerRoot = cfg.ServerRoot ?? "http://localhost/";
result.LaunchFrequency = cfg.LaunchFrequency != 0 ? cfg.LaunchFrequency : 1;
result.ConnectionStringName = cfg.ConnectionStringName ?? "default";
result.Formats = cfg.Formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico";
result.SqlMaxResults = cfg.SqlMaxResults != 0 ? cfg.SqlMaxResults : 1000;
result.MaxDegreeOfParallelism = cfg.MaxDegreeOfParallelism != 0 ? cfg.MaxDegreeOfParallelism : 10;
result.AvailableFileSize = cfg.AvailableFileSize ?? 100L * 1024L * 1024L;
result.AttemptsLimit = cfg.AttemptsLimit ?? 3;
result.AttemptWaitInterval = cfg.AttemptWaitInterval != 0 ? cfg.AttemptWaitInterval : 1000;
result.ThumbnaillHeight = cfg.ThumbnaillHeight != 0 ? cfg.ThumbnaillHeight : 128;
result.ThumbnaillWidth = cfg.ThumbnaillWidth != 0 ? cfg.ThumbnaillWidth : 192;
return result;
}
#region worker settings

View File

@ -40,10 +40,10 @@ namespace ASC.Files.ThumbnailBuilder
public Worker(
IServiceProvider serviceProvider,
IOptionsMonitor<ILog> options,
ThumbnailSettings thumbnailSettings)
Common.Utils.ConfigurationExtension configurationExtension)
{
this.serviceProvider = serviceProvider;
this.thumbnailSettings = thumbnailSettings;
this.thumbnailSettings = ThumbnailSettings.GetInstance(configurationExtension);
logger = options.Get("ASC.Files.ThumbnailBuilder");
}
@ -113,7 +113,6 @@ namespace ASC.Files.ThumbnailBuilder
services.TryAdd<FileDataProvider>();
services.TryAdd<BuilderQueue<int>>();
services.TryAdd<Builder<int>>();
services.TryAdd<ThumbnailSettings>();
}
}
}

View File

@ -175,6 +175,7 @@ namespace ASC.Web.Api.Controllers
}
[Create("logout")]
[Read("logout")]// temp fix
public void Logout()
{
CookiesManager.ClearCookies(CookiesType.AuthKey);
@ -225,14 +226,14 @@ namespace ASC.Web.Api.Controllers
}
[Create(@"sendsms", false)]
public AuthenticationTokenData SendSmsCodeFromBody([FromBody]AuthModel model)
public AuthenticationTokenData SendSmsCodeFromBody([FromBody] AuthModel model)
{
return SendSmsCode(model);
}
[Create(@"sendsms", false)]
[Consumes("application/x-www-form-urlencoded")]
public AuthenticationTokenData SendSmsCodeFromForm([FromForm]AuthModel model)
public AuthenticationTokenData SendSmsCodeFromForm([FromForm] AuthModel model)
{
return SendSmsCode(model);
}
@ -298,7 +299,7 @@ namespace ASC.Web.Api.Controllers
CookiesManager.SetCookies(CookiesType.AuthKey, token);
MessageService.Send(viaEmail ? MessageAction.LoginSuccessViaApi : MessageAction.LoginSuccessViaApiSocialAccount);
var tenant = TenantManager.GetCurrentTenant().TenantId;
var expires = TenantCookieSettingsHelper.GetExpiresTime(tenant);
@ -347,7 +348,7 @@ namespace ASC.Web.Api.Controllers
var token = SecurityContext.AuthenticateMe(user.ID);
MessageService.Send(sms ? MessageAction.LoginSuccessViaApiSms : MessageAction.LoginSuccessViaApiTfa);
;
;
var expires = TenantCookieSettingsHelper.GetExpiresTime(tenant);
var result = new AuthenticationTokenData
@ -444,7 +445,7 @@ namespace ASC.Web.Api.Controllers
{
thirdPartyProfile = ProviderManager.GetLoginProfile(memberModel.Provider, memberModel.AccessToken);
}
memberModel.UserName = thirdPartyProfile.EMail;
user = GetUserByThirdParty(thirdPartyProfile);

View File

@ -256,8 +256,8 @@ const Editor = () => {
}
if (!doc && !successAuth) {
sessionStorage.setItem('redirectPath', window.location.href);
localStorage.setItem("redirectPath", window.location.href);
window.open(
combineUrl(
AppServerConfig.proxyURL,

View File

@ -209,10 +209,10 @@ const Form = (props) => {
thirdPartyLogin(profile.Serialized)
.then(() => {
setIsLoading(true);
const redirectPath = sessionStorage.getItem("redirectPath");
const redirectPath = localStorage.getItem("redirectPath");
if (redirectPath) {
sessionStorage.removeItem("redirectPath");
localStorage.removeItem("redirectPath");
window.location.href = redirectPath;
} else history.push(defaultPage);
})
@ -312,10 +312,10 @@ const Form = (props) => {
login(userName, hash)
.then((res) => {
const { url, user, hash } = res;
const redirectPath = sessionStorage.getItem("redirectPath");
const redirectPath = localStorage.getItem("redirectPath");
if (redirectPath) {
sessionStorage.removeItem("redirectPath");
localStorage.removeItem("redirectPath");
window.location.href = redirectPath;
} else history.push(url, { user, hash });
})