This commit is contained in:
Nikita Gopienko 2019-08-13 16:24:59 +03:00
commit 74e49623f5
168 changed files with 7081 additions and 10317 deletions

View File

@ -0,0 +1,48 @@
/*
*
* (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.
*
*/
#region usings
using System.Collections.Generic;
using System.Runtime.Serialization;
#endregion
namespace ASC.Api.Collections
{
[CollectionDataContract(Name = "hash", Namespace = "", ItemName = "entry", KeyName = "key", ValueName = "value")]
public class ItemDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public ItemDictionary()
{
}
public ItemDictionary(IDictionary<TKey, TValue> items)
: base(items)
{
}
}
}

View File

@ -0,0 +1,43 @@
/*
*
* (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.Runtime.Serialization;
namespace ASC.Api.Collections
{
[DataContract]
public class ItemKeyValuePair<TKey, TValue>
{
[DataMember]
public TKey Key { get; set; }
[DataMember]
public TValue Value { get; set; }
}
}

View File

@ -0,0 +1,52 @@
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using ASC.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace ASC.Api.Core.Middleware
{
public class CultureMiddleware
{
private readonly RequestDelegate next;
public CultureMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
CultureInfo culture = null;
if (SecurityContext.IsAuthenticated)
{
var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
if (!string.IsNullOrEmpty(user.CultureName))
{
culture = user.GetCulture();
}
}
if (culture == null)
{
culture = CoreContext.TenantManager.GetCurrentTenant().GetCulture();
}
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
await next.Invoke(context);
}
}
public static class CultureMiddlewareExtensions
{
public static IApplicationBuilder UseCultureMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CultureMiddleware>();
}
}
}

View File

@ -0,0 +1,35 @@
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using ASC.Common.Web;
using ASC.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace ASC.Api.Core.Middleware
{
public class DisposeMiddleware
{
private readonly RequestDelegate next;
public DisposeMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
context.Response.RegisterForDispose(new DisposableHttpContext(context));
await next.Invoke(context);
}
}
public static class DisposeMiddlewareExtensions
{
public static IApplicationBuilder UseDisposeMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<DisposeMiddleware>();
}
}
}

View File

@ -33,9 +33,9 @@
<PackageReference Include="Autofac" Version="4.9.3" />
<PackageReference Include="Autofac.Configuration" Version="4.1.0" />
<PackageReference Include="Confluent.Kafka" Version="1.1.0" />
<PackageReference Include="Google.Protobuf" Version="3.9.0-rc1" />
<PackageReference Include="Grpc" Version="1.22.0" />
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="Google.Protobuf" Version="3.9.1" />
<PackageReference Include="Grpc" Version="2.23.0-pre1" />
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -52,11 +52,11 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.CloudFront" Version="3.3.101.17" />
<PackageReference Include="AWSSDK.Core" Version="3.3.103.14" />
<PackageReference Include="AWSSDK.S3" Version="3.3.104.2" />
<PackageReference Include="AWSSDK.SimpleEmail" Version="3.3.101.20" />
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="AWSSDK.CloudFront" Version="3.3.101.27" />
<PackageReference Include="AWSSDK.Core" Version="3.3.103.24" />
<PackageReference Include="AWSSDK.S3" Version="3.3.104.12" />
<PackageReference Include="AWSSDK.SimpleEmail" Version="3.3.101.30" />
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Security.Authentication;
using System.Text;
namespace ASC.Core.Common.Security
{
public class BruteForceCredentialException : InvalidCredentialException
{
public BruteForceCredentialException()
{
}
public BruteForceCredentialException(string message) : base(message)
{
}
}
}

View File

@ -14,14 +14,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Api.Gax" Version="2.9.0" />
<PackageReference Include="Google.Api.Gax.Rest" Version="2.9.0" />
<PackageReference Include="Google.Apis" Version="1.40.2" />
<PackageReference Include="Google.Apis.Auth" Version="1.40.2" />
<PackageReference Include="Google.Apis.Core" Version="1.40.2" />
<PackageReference Include="Google.Apis.Storage.v1" Version="1.40.2.1635" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="2.4.0-beta02" />
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="Google.Api.Gax" Version="2.10.0-beta02" />
<PackageReference Include="Google.Api.Gax.Rest" Version="2.10.0-beta02" />
<PackageReference Include="Google.Apis" Version="1.40.3" />
<PackageReference Include="Google.Apis.Auth" Version="1.40.3" />
<PackageReference Include="Google.Apis.Core" Version="1.40.3" />
<PackageReference Include="Google.Apis.Storage.v1" Version="1.40.3.1635" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="2.4.0-beta03" />
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="DotNetOpenAuth.Ultimate" Version="4.3.4.13329" />
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.5.0" />
<PackageReference Include="CommandLineParser" Version="2.6.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.0.0-preview7.19362.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0-preview7.19362.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0-preview7.19362.4" />

View File

@ -31,13 +31,14 @@ using System.Linq;
using System.Xml;
using ASC.Common.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Formatting = Newtonsoft.Json.Formatting;
namespace ASC.Resource.Manager
{
public static class JsonManager
{
public static void UploadJson(string fileName, Stream fileStream, string projectName, string moduleName)
public static void Upload(string fileName, Stream fileStream, string projectName, string moduleName)
{
var culture = GetCultureFromFileName(fileName);
@ -99,7 +100,7 @@ namespace ASC.Resource.Manager
}
}
public static void ExportJson(string project, string module, string language, string exportPath, bool toJson = true, bool withDefaultValue = true)
public static void Export(string project, string module, string language, string exportPath, string key = null)
{
var filter = new ResCurrent
{
@ -119,10 +120,43 @@ namespace ASC.Resource.Manager
foreach (var fileWords in words)
{
var wordsDictionary = new Dictionary<string, object>();
var firstWord = fileWords.FirstOrDefault();
var fileName = firstWord == null
? module
: Path.GetFileNameWithoutExtension(firstWord.ResFile.FileName);
var zipFileName = Path.Combine(exportPath, language == "Neutral" ? "en" : language, $"{fileName}.json");
foreach (var word in fileWords.OrderBy(x => x.Title).Where(word => !wordsDictionary.ContainsKey(word.Title)))
var dirName = Path.GetDirectoryName(zipFileName);
if (!Directory.Exists(dirName))
{
if (string.IsNullOrEmpty(word.ValueTo) && !withDefaultValue) continue;
Directory.CreateDirectory(dirName);
}
var toAdd = new List<ResWord>();
if (!string.IsNullOrEmpty(key))
{
if (File.Exists(zipFileName))
{
var jObject = JObject.Parse(File.ReadAllText(zipFileName));
foreach(var j in jObject)
{
toAdd.Add(new ResWord { Title = j.Key, ValueFrom = j.Value.ToString() });
}
}
if (!toAdd.Any(r => r.Title == key))
{
toAdd.Add(fileWords.FirstOrDefault(r => r.Title == key));
}
}
else
{
toAdd.AddRange(fileWords.OrderBy(x => x.Title).Where(word => !wordsDictionary.ContainsKey(word.Title)));
}
foreach (var word in toAdd)
{
if (string.IsNullOrEmpty(word.ValueTo)) continue;
var newVal = word.ValueTo ?? word.ValueFrom;
@ -135,66 +169,11 @@ namespace ASC.Resource.Manager
wordsDictionary.Add(newKey.Keys.First(), newKey.Values.First());
}
var firstWord = fileWords.FirstOrDefault();
var fileName = firstWord == null
? module
: Path.GetFileNameWithoutExtension(firstWord.ResFile.FileName);
string zipFileName = null;
if (toJson)
{
zipFileName = Path.Combine(exportPath, language == "Neutral" ? "en" : language, $"{fileName}.json");
}
else
{
zipFileName = Path.Combine(exportPath, project, module, $"{fileName}{(language == "Neutral" ? string.Empty : "." + language)}.resx");
}
var dirName = Path.GetDirectoryName(zipFileName);
if (!Directory.Exists(dirName))
{
Directory.CreateDirectory(dirName);
}
using TextWriter writer = new StreamWriter(zipFileName);
if (toJson)
{
var obj = JsonConvert.SerializeObject(wordsDictionary, Formatting.Indented);
writer.Write(obj);
}
else
{
var data = new XmlDocument();
var resources = data.CreateElement("resources");
foreach (var ind in wordsDictionary)
{
var stringAttr = data.CreateAttribute("name");
stringAttr.Value = ind.Key;
var child = data.CreateElement("string");
child.Attributes.Append(stringAttr);
child.InnerText = ind.Value.ToString();
resources.AppendChild(child);
}
data.AppendChild(resources);
var settings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
OmitXmlDeclaration = false,
ConformanceLevel = ConformanceLevel.Fragment
};
using var xmlTextWriter = XmlWriter.Create(writer, settings);
data.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
}
var obj = JsonConvert.SerializeObject(wordsDictionary, Formatting.Indented);
writer.Write(obj);
}
}

View File

@ -10,10 +10,19 @@ namespace ASC.Resource.Manager
[Option('m', "module", Required = false, HelpText = "Module")]
public string Module { get; set; }
[Option('e', "exportpath", Required = false, HelpText = "Export Path")]
[Option('e', "exportpath", Required = false, HelpText = "Export Path", Default = "..\\..\\..\\..\\ASC.Common\\")]
public string ExportPath { get; set; }
[Option('c', "culture", Required = false, HelpText = "Culture")]
public string Culture { get; set; }
[Option('f', "format", Required = false, HelpText = "Format", Default = "xml")]
public string Format { get; set; }
[Option('k', "key", Required = false, HelpText = "Key", Default = "")]
public string Key { get; set; }
public void Deconstruct(out string project, out string module, out string exportPath, out string culture, out string format, out string key)
=> (project, module, exportPath, culture, format, key) = (Project, Module, ExportPath, Culture, Format, Key);
}
}

View File

@ -30,19 +30,31 @@ namespace ASC.Resource.Manager
var cultures = new List<string>();
var projects = new List<ResFile>();
var enabledSettings = new EnabledSettings();
Action<string, string, string, string, string> export = null;
try
{
var projectName = options.Project;
var moduleName = options.Module;
var exportPath = options.ExportPath;
var culture = options.Culture;
var (project, module, exportPath, culture, format, key) = options;
if(format == "json")
{
export = JsonManager.Export;
}
else
{
export = ResxManager.Export;
}
if (string.IsNullOrEmpty(exportPath))
{
exportPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
if (!Path.IsPathRooted(exportPath))
{
exportPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), exportPath));
}
if (!Directory.Exists(exportPath))
{
Console.WriteLine("Error!!! Export path doesn't exist! Please enter a valid directory path.");
@ -53,7 +65,7 @@ namespace ASC.Resource.Manager
cultures = ResourceData.GetCultures().Where(r => r.Available).Select(r => r.Title).Intersect(enabledSettings.Langs).ToList();
projects = ResourceData.GetAllFiles();
ExportWithProject(projectName, moduleName, culture, exportPath);
ExportWithProject(project, module, culture, exportPath, key);
Console.WriteLine("The data has been successfully exported!");
}
@ -62,47 +74,44 @@ namespace ASC.Resource.Manager
Console.WriteLine(err);
}
void ExportWithProject(string projectName, string moduleName, string culture, string exportPath)
void ExportWithProject(string projectName, string moduleName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(projectName))
{
ExportWithModule(projectName, moduleName, culture, exportPath);
ExportWithModule(projectName, moduleName, culture, exportPath, key);
}
else
{
foreach (var p in projects.Select(r => r.ProjectName).Intersect(enabledSettings.Projects))
{
ExportWithModule(p, moduleName, culture, exportPath);
ExportWithModule(p, moduleName, culture, exportPath, key);
}
}
}
void ExportWithModule(string projectName, string moduleName, string culture, string exportPath)
void ExportWithModule(string projectName, string moduleName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(moduleName))
{
ExportWithCulture(projectName, moduleName, culture, exportPath);
ExportWithCulture(projectName, moduleName, culture, exportPath, key);
}
else
{
foreach (var m in projects.Where(r => r.ProjectName == projectName).Select(r => r.ModuleName))
{
ExportWithCulture(projectName, m, culture, exportPath);
ExportWithCulture(projectName, m, culture, exportPath, key);
}
}
}
void ExportWithCulture(string projectName, string moduleName, string culture, string exportPath)
void ExportWithCulture(string projectName, string moduleName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(culture))
{
JsonManager.ExportJson(projectName, moduleName, culture, exportPath);
export(projectName, moduleName, culture, exportPath, key);
}
else
{
foreach (var c in cultures)
{
JsonManager.ExportJson(projectName, moduleName, c, exportPath);
}
ParallelEnumerable.ForAll(cultures.AsParallel(), c => export(projectName, moduleName, c, exportPath, key));
}
}
}

View File

@ -0,0 +1,114 @@
/*
*
* (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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Resources;
namespace ASC.Resource.Manager
{
public class ResxManager
{
public static void Export(string project, string module, string language, string exportPath, string key = null)
{
var filter = new ResCurrent
{
Project = new ResProject { Name = project },
Module = new ResModule { Name = module },
Language = new ResCulture { Title = language }
};
var words = ResourceData.GetListResWords(filter, string.Empty).GroupBy(x => x.ResFile.FileID).ToList();
if (!words.Any())
{
Console.WriteLine("Error!!! Can't find appropriate project and module. Possibly wrong names!");
return;
}
foreach (var fileWords in words)
{
var wordsDictionary = new Dictionary<string, object>();
var firstWord = fileWords.FirstOrDefault();
var fileName = firstWord == null
? module
: Path.GetFileNameWithoutExtension(firstWord.ResFile.FileName);
var zipFileName = Path.Combine(exportPath, $"{fileName}{(language == "Neutral" ? string.Empty : "." + language)}.resx");
var dirName = Path.GetDirectoryName(zipFileName);
if (!Directory.Exists(dirName))
{
Directory.CreateDirectory(dirName);
}
var toAdd = new List<ResWord>();
if (!string.IsNullOrEmpty(key))
{
var keys = key.Split(",");
if (File.Exists(zipFileName))
{
using var resXResourceReader = new ResXResourceReader(zipFileName);
foreach (var v in resXResourceReader.Cast<DictionaryEntry>())
{
toAdd.Add(new ResWord { Title = v.Key.ToString(), ValueFrom = v.Value?.ToString() });
}
}
foreach (var k in keys)
{
if (!toAdd.Any(r => r.Title == k))
{
var exists = fileWords.FirstOrDefault(r => r.Title == k);
if (exists != null)
{
toAdd.Add(exists);
}
}
}
}
else
{
toAdd.AddRange(fileWords.Where(word => !wordsDictionary.ContainsKey(word.Title)));
}
using var resXResourceWriter = new ResXResourceWriter(zipFileName);
foreach (var word in toAdd.Where(r=> r != null && !string.IsNullOrEmpty(r.ValueTo)).OrderBy(x => x.Title))
{
resXResourceWriter.AddResource(word.Title, word.ValueTo);
}
resXResourceWriter.Generate();
resXResourceWriter.Close();
}
}
}
}

View File

@ -14,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PackageReference Include="Grpc.Tools" Version="2.23.0-pre1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -56,7 +56,7 @@ const App = ({ settings }) => {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
}

View File

@ -1,123 +1,22 @@
import React, { useState } from 'react';
import React, { useCallback } from 'react';
import { connect } from 'react-redux';
import {
TreeMenu,
TreeNode,
Icons
} from "asc-web-components";
import { getTreeGroups } from '../../../store/people/selectors';
import { selectGroup } from '../../../store/people/actions';
const PeopleTreeMenu = props => {
const { data } = props;
const [gData, setGData] = useState(data);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const [expandedKeys, setExpandedKeys] = useState([
"0-0-key",
"0-0-0-key",
"0-0-0-0-key"
]);
const onDragStart = info => {
info.event.persist();
};
const onDragEnter = info => {
setExpandedKeys(info.expandedKeys);
};
const onDrop = info => {
info.event.persist();
const dropKey = info.node.props.eventKey;
const dragKey = info.dragNode.props.eventKey;
const dropPos = info.node.props.pos.split("-");
const dropPosition =
info.dropPosition - Number(dropPos[dropPos.length - 1]);
const getItems = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
callback(item, index, arr);
return;
}
if (item.children) {
getItems(item.children, key, callback);
}
});
};
const data = [...gData];
let dragObj;
getItems(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
if (!info.dropToGap) {
getItems(data, dropKey, item => {
item.children = item.children || [];
item.children.push(dragObj);
});
} else if (
(info.node.props.children || []).length > 0 &&
info.node.props.expanded &&
dropPosition === 1
) {
getItems(data, dropKey, item => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else {
let ar;
let i;
getItems(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
setGData(data);
};
const onExpand = expandedKeys => {
setExpandedKeys(expandedKeys);
setAutoExpandParent(false);
};
const getItems = data => {
return data.map(item => {
if (item.children && item.children.length) {
return (
<TreeNode
title={item.title}
key={item.key}
icon={
item.root ? (
<Icons.CatalogDepartmentsIcon
size="scale"
isfill={true}
color="dimgray"
/>
) : (
""
)
}
>
{getItems(item.children)}
</TreeNode>
);
}
const getItems = data => {
return data.map(item => {
if (item.children && item.children.length) {
return (
<TreeNode
key={item.key}
title={item.title}
key={item.key}
icon={
!item.root ? (
<Icons.CatalogFolderIcon
item.root ? (
<Icons.CatalogDepartmentsIcon
size="scale"
isfill={true}
color="dimgray"
@ -126,10 +25,39 @@ const PeopleTreeMenu = props => {
""
)
}
/>
>
{getItems(item.children)}
</TreeNode>
);
});
};
}
return (
<TreeNode
key={item.key}
title={item.title}
icon={
!item.root ? (
<Icons.CatalogFolderIcon
size="scale"
isfill={true}
color="dimgray"
/>
) : (
""
)
}
/>
);
});
};
const PeopleTreeMenu = props => {
const { data, selectGroup, defaultSelectedKeys } = props;
console.log("PeopleTreeMenu", props);
const onSelect = useCallback(data => {
selectGroup(data && data.length === 1 && data[0] !== "root" ? data[0] : null);
}, [selectGroup])
const switcherIcon = obj => {
if (obj.isLeaf) {
@ -154,26 +82,39 @@ const PeopleTreeMenu = props => {
multiple={false}
showIcon={true}
defaultExpandAll={true}
defaultExpandParent={true}
onExpand={onExpand}
autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys}
onDragStart={info => onDragStart(info)}
onDrop={info => onDrop(info)}
onDragEnter={onDragEnter}
switcherIcon={switcherIcon}
onSelect={onSelect}
defaultSelectedKeys={defaultSelectedKeys}
>
{getItems(gData)}
{getItems(data)}
</TreeMenu>
);
};
const ArticleBodyContent = ({ treeData }) => <PeopleTreeMenu data={treeData} />;
const ArticleBodyContent = props => <PeopleTreeMenu {...props} />;
const getTreeGroups = (groups) => {
const treeData = [
{
key: "root",
title: "Departments",
root: true,
children: groups.map(g => {
return {
key: g.id, title: g.name, root: false
};
}) || []
}
];
return treeData;
};
function mapStateToProps(state) {
return {
treeData: getTreeGroups(state.people.groups)
data: getTreeGroups(state.people.groups),
defaultSelectedKeys: state.people.selectedGroup ? [state.people.selectedGroup] : ["root"]
};
}
export default connect(mapStateToProps)(ArticleBodyContent);
export default connect(mapStateToProps, { selectGroup })(ArticleBodyContent);

View File

@ -74,7 +74,7 @@ ArticleMainButtonContent.propTypes = {
const mapStateToProps = (state) => {
return {
isAdmin: isAdmin(state.auth),
settings: state.settings
settings: state.auth.settings
}
}

View File

@ -66,8 +66,8 @@ function mapStateToProps(state) {
auth: state.auth,
availableModules: getAvailableModules(state.auth.modules),
currentUser: state.auth.user,
currentModuleId: state.settings.currentProductId,
settings: state.settings
currentModuleId: state.auth.settings.currentProductId,
settings: state.auth.settings
};
}

View File

@ -38,7 +38,7 @@ SectionHeaderContent.defaultProps = {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
};

View File

@ -23,7 +23,7 @@ class GroupAction extends React.Component {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
}

View File

@ -1,10 +1,10 @@
import React, { memo, useCallback } from "react";
import React, { memo } from "react";
import { withRouter } from "react-router";
import { connect } from "react-redux";
import {
ContentRow,
toastr,
Scrollbar,
CustomScrollbarsVirtualList,
EmptyScreenContainer,
Icons,
Link
@ -26,34 +26,6 @@ import { isAdmin } from "../../../../../store/auth/selectors";
import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
const CustomScrollbars = ({ onScroll, forwardedRef, style, children }) => {
const refSetter = useCallback(
scrollbarsRef => {
if (scrollbarsRef) {
forwardedRef(scrollbarsRef.view);
} else {
forwardedRef(null);
}
},
[forwardedRef]
);
return (
<Scrollbar
ref={refSetter}
style={{ ...style, overflow: "hidden" }}
onScroll={onScroll}
stype="mediumBlack"
>
{children}
</Scrollbar>
);
};
const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
<CustomScrollbars {...props} forwardedRef={ref} />
));
const Row = memo(
({
data,
@ -232,7 +204,7 @@ const mapStateToProps = state => {
selected: state.people.selected,
users: state.people.users,
isAdmin: isAdmin(state.auth),
settings: state.settings
settings: state.auth.settings
};
};

View File

@ -41,7 +41,7 @@ const UserContent = ({user, history,settings }) => {
{displayName &&
<Link
isSemitransparent={status === "pending"}
type="action"
type="page"
title={displayName}
isBold={true}
fontSize={15}
@ -141,7 +141,7 @@ const UserContent = ({user, history,settings }) => {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
}

View File

@ -1,5 +1,7 @@
import React from 'react';
import { GroupButtonsMenu, DropDownItem, Text, toastr } from 'asc-web-components';
import { GroupButtonsMenu, DropDownItem, Text, toastr, ContextMenuButton } from 'asc-web-components';
import { connect } from 'react-redux';
import { getSelectedGroup } from '../../../../../store/people/selectors';
const getPeopleItems = (onSelect) => [
{
@ -45,13 +47,34 @@ const getPeopleItems = (onSelect) => [
}
];
const contextOptions = () => {
return [
{
key: "edit-group",
label: "Edit",
onClick: toastr.success.bind(this, "Edit group action")
},
{
key: "delete-group",
label: "Delete",
onClick: toastr.success.bind(this, "Delete group action")
}
];
};
const wrapperStyle = {
display: "flex",
alignItems: "center"
};
const SectionHeaderContent = React.memo(({
isHeaderVisible,
isHeaderIndeterminate,
isHeaderChecked,
onCheck,
onSelect,
onClose
onClose,
group
}) => {
console.log("SectionHeaderContent render");
const menuItems = getPeopleItems(onSelect);
@ -71,9 +94,27 @@ const SectionHeaderContent = React.memo(({
/>
</div>
) : (
<Text.ContentHeader>People</Text.ContentHeader>
group
? <div style={wrapperStyle}>
<Text.ContentHeader>{group.name}</Text.ContentHeader>
<ContextMenuButton
directionX='right'
title='Actions'
iconName='VerticalDotsIcon'
size={16}
color='#A3A9AE'
getData={contextOptions}
isDisabled={false}/>
</div>
: <Text.ContentHeader>People</Text.ContentHeader>
)
);
});
export default SectionHeaderContent;
const mapStateToProps = (state) => {
return {
group: getSelectedGroup(state.people.groups, state.people.selectedGroup)
}
}
export default connect(mapStateToProps)(SectionHeaderContent);

View File

@ -115,6 +115,7 @@ const SectionPagingContent = ({
openDirection="top"
selectedPage={filter.page} //FILTER CURRENT PAGE
selectedCount={filter.pageCount} //FILTER PAGE COUNT
emptyPagePlaceholder="1 of 1"
/>
);
};

View File

@ -253,7 +253,7 @@ const SectionBodyContent = (props) => {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
}

View File

@ -88,7 +88,7 @@ const SectionHeaderContent = (props) => {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
}

View File

@ -44,7 +44,7 @@ SectionHeaderContent.defaultProps = {
function mapStateToProps(state) {
return {
settings: state.settings
settings: state.auth.settings
};
};

View File

@ -6,6 +6,7 @@ import { fetchPeople } from '../people/actions';
export const LOGIN_POST = 'LOGIN_POST';
export const SET_CURRENT_USER = 'SET_CURRENT_USER';
export const SET_MODULES = 'SET_MODULES';
export const SET_SETTINGS = 'SET_SETTINGS';
export const SET_IS_LOADED = 'SET_IS_LOADED';
export const LOGOUT = 'LOGOUT';
@ -23,6 +24,13 @@ export function setModules(modules) {
};
};
export function setSettings(settings) {
return {
type: SET_SETTINGS,
settings
};
};
export function setIsLoaded(isLoaded) {
return {
type: SET_IS_LOADED,
@ -38,11 +46,13 @@ export function setLogout() {
export function getUserInfo(dispatch) {
return api.getUser()
.then((res) => dispatch(setCurrentUser(res.data.response)))
.then(res => dispatch(setCurrentUser(res.data.response)))
.then(() => api.getModulesList())
.then((res) => dispatch(setModules(res.data.response)))
.then(res => dispatch(setModules(res.data.response)))
.then(() => api.getSettings())
.then(res => dispatch(setSettings(res.data.response)))
.then(() => api.getGroupList())
.then((res) => dispatch(setGroups(res.data.response)))
.then(res => dispatch(setGroups(res.data.response)))
.then(() => dispatch(fetchPeople()))
.then(() => dispatch(setIsLoaded(true)));
};

View File

@ -1,11 +1,30 @@
import { SET_CURRENT_USER, SET_MODULES, SET_IS_LOADED, LOGOUT } from './actions';
import { SET_CURRENT_USER, SET_MODULES, SET_IS_LOADED, LOGOUT, SET_SETTINGS } from './actions';
import isEmpty from 'lodash/isEmpty';
import config from "../../../package.json";
const initialState = {
isAuthenticated: false,
isLoaded: false,
user: {},
modules: []
modules: [],
settings: {
currentProductId: "f4d98afd-d336-4332-8778-3c6945c81ea0",
culture: "en-US",
trustedDomains: [],
trustedDomainsType: 1,
timezone: "UTC",
utcOffset: "00:00:00",
utcHoursOffset: 0,
homepage: config.homepage,
datePattern: "M/d/yyyy",
datePatternJQ: "00/00/0000",
dateTimePattern: "dddd, MMMM d, yyyy h:mm:ss tt",
datepicker: {
datePattern: "mm/dd/yy",
dateTimePattern: "DD, mm dd, yy h:mm:ss tt",
timePattern: "h:mm tt"
}
}
};
const authReducer = (state = initialState, action) => {
@ -19,6 +38,10 @@ const authReducer = (state = initialState, action) => {
return Object.assign({}, state, {
modules: action.modules
});
case SET_SETTINGS:
return Object.assign({}, state, {
settings: { ...state.settings, ...action.settings }
});
case SET_IS_LOADED:
return Object.assign({}, state, {
isLoaded: action.isLoaded

View File

@ -8,6 +8,7 @@ export const SELECT_USER = 'SELECT_USER';
export const DESELECT_USER = 'DESELECT_USER';
export const SET_SELECTED = 'SET_SELECTED';
export const SET_FILTER = 'SET_FILTER';
export const SELECT_GROUP = 'SELECT_GROUP';
export function setUsers(users) {
return {
@ -37,6 +38,13 @@ export function setSelected(selected) {
};
};
export function selectGroup(groupId) {
return {
type: SELECT_GROUP,
groupId
};
};
export function selectUser(user) {
return {
type: SELECT_USER,

View File

@ -5,7 +5,8 @@ import {
SELECT_USER,
DESELECT_USER,
SET_SELECTED,
SET_FILTER
SET_FILTER,
SELECT_GROUP
} from "./actions";
import { isUserSelected, skipUser, getUsersBySelected } from './selectors';
import Filter from "./filter";
@ -15,6 +16,7 @@ const initialState = {
groups: [],
selection: [],
selected: "none",
selectedGroup: null,
filter: Filter.getDefault()
};
@ -53,6 +55,10 @@ const peopleReducer = (state = initialState, action) => {
return Object.assign({}, state, {
filter: action.filter
});
case SELECT_GROUP:
return Object.assign({}, state, {
selectedGroup: action.groupId
});
default:
return state;
}

View File

@ -23,23 +23,6 @@ export function skipUser(selection, userId) {
});
};
export function getTreeGroups(groups) {
const treeData = [
{
key: "0-0",
title: "Departments",
root: true,
children: groups.map(g => {
return {
key: g.id, title: g.name, root: false
};
}) || []
}
];
return treeData;
};
export const getUserStatus = user => {
if (user.status === EmployeeStatus.Active && user.activationStatus === EmployeeActivationStatus.Activated) {
return "normal";
@ -128,4 +111,8 @@ export function getUsersBySelected(users, selected) {
export function isUserDisabled(user) {
return getUserStatus(user) === "disabled";
};
};
export function getSelectedGroup(groups, selectedGroupId) {
return find(groups, (group) => group.id === selectedGroupId);
}

View File

@ -2,15 +2,13 @@ import { combineReducers } from 'redux';
import authReducer from './auth/reducers';
import peopleReducer from './people/reducers';
import profileReducer from './profile/reducers';
import settingsReducer from './settings/reducer';
import { reducer as formReducer } from 'redux-form';
const rootReducer = combineReducers({
auth: authReducer,
people: peopleReducer,
profile: profileReducer,
form: formReducer,
settings: settingsReducer
form: formReducer
});
export default rootReducer;

View File

@ -26,6 +26,12 @@ export function getModulesList() {
});
};
export function getSettings() {
return IS_FAKE
? fakeApi.getSettings()
: axios.get(`${API_URL}/settings.json`);
};
export function getUser(userId) {
return IS_FAKE ? fakeApi.getUser() : axios.get(`${API_URL}/people/${userId || "@self"}.json`);
};

View File

@ -39,6 +39,20 @@ export function getModulesList() {
return fakeResponse(data);
};
export function getSettings() {
const data = {
"timezone": "Russian Standard Time;180;(UTC+03:00) Moscow, St. Petersburg;Russia TZ 2 Standard Time;Russia TZ 2 Daylight Time;[01:01:0001;12:31:2010;60;[0;02:00:00;3;5;0;];[0;03:00:00;10;5;0;];][01:01:2011;12:31:2011;60;[0;02:00:00;3;5;0;];[0;00:00:00;1;1;6;];][01:01:2012;12:31:2012;0;[1;00:00:00;1;1;];[1;00:00:00.001;1;1;];60;][01:01:2013;12:31:2013;0;[1;00:00:00;1;1;];[1;00:00:00.001;1;1;];60;][01:01:2014;12:31:2014;60;[0;00:00:00;1;1;3;];[0;02:00:00;10;5;0;];];",
"trustedDomains": [],
"trustedDomainsType": 1,
"culture": "ru-RU",
"utcOffset": "03:00:00",
"utcHoursOffset": 3
};
return fakeResponse(data);
};
export function getUser() {
const data = {
"index": "a",

View File

@ -1,25 +0,0 @@
import config from "../../../package.json";
const initialState = {
currentProductId: "f4d98afd-d336-4332-8778-3c6945c81ea0",
currentCulture: "en-US",
currentCultureName: "en-us",
homepage: config.homepage,
datePattern: "M/d/yyyy",
datePatternJQ: "00/00/0000",
dateTimePattern: "dddd, MMMM d, yyyy h:mm:ss tt",
datepicker: {
datePattern: "mm/dd/yy",
dateTimePattern: "DD, mm dd, yy h:mm:ss tt",
timePattern: "h:mm tt"
}
};
const settingsReducer = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
export default settingsReducer;

View File

@ -28,23 +28,37 @@
<ProjectReference Include="..\..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Resources\Resources.tt">
<LastGenOutput>Resources.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Resources.cs">
<Compile Update="Resources\PeopleResource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.tt</DependentUpon>
<DependentUpon>PeopleResource.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\PeopleResource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>PeopleResource.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Resources\PeopleResource.ru.resx" >
<DependentUpon>PeopleResource.resx</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="Resources\PeopleResource.de.resx" >
<DependentUpon>PeopleResource.resx</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="Resources\PeopleResource.es.resx" >
<DependentUpon>PeopleResource.resx</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="Resources\PeopleResource.fr.resx" >
<DependentUpon>PeopleResource.resx</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="Resources\PeopleResource.it.resx" >
<DependentUpon>PeopleResource.resx</DependentUpon>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -19,6 +19,7 @@ using ASC.FederatedLogin.Profile;
using ASC.MessagingSystem;
using ASC.People;
using ASC.People.Models;
using ASC.People.Resources;
using ASC.Web.Api.Models;
using ASC.Web.Api.Routing;
using ASC.Web.Core;
@ -529,7 +530,7 @@ namespace ASC.Employee.Core.Controllers
UserPhotoManager.RemovePhoto(Tenant, user.ID);
CoreContext.UserManager.DeleteUser(Tenant, user.ID);
QueueWorkerRemove.Start(TenantProvider.CurrentTenantID, user, SecurityContext.CurrentAccount.ID, false);
QueueWorkerRemove.Start(Tenant.TenantId, user, SecurityContext.CurrentAccount.ID, false);
MessageService.Send(MessageAction.UserDeleted, MessageTarget.Create(user.ID), userName);
@ -754,9 +755,9 @@ namespace ASC.Employee.Core.Controllers
[AllowAnonymous]
[Create("password", false)]
public string SendUserPassword(string email)
public string SendUserPassword(MemberModel memberModel)
{
var userInfo = UserManagerWrapper.SendUserPassword(Tenant.TenantId, email, MessageService, HttpContext);
var userInfo = UserManagerWrapper.SendUserPassword(Tenant.TenantId, memberModel.Email, MessageService, HttpContext);
return string.Format(Resource.MessageYourPasswordSuccessfullySendedToEmail, userInfo.Email);
}
@ -964,7 +965,7 @@ namespace ASC.Employee.Core.Controllers
UserPhotoManager.RemovePhoto(Tenant, user.ID);
CoreContext.UserManager.DeleteUser(Tenant,user.ID);
QueueWorkerRemove.Start(TenantProvider.CurrentTenantID, user, SecurityContext.CurrentAccount.ID, false);
QueueWorkerRemove.Start(Tenant.TenantId, user, SecurityContext.CurrentAccount.ID, false);
}
MessageService.Send(MessageAction.UsersDeleted, MessageTarget.Create(users.Select(x => x.ID)), userNames);
@ -1044,7 +1045,7 @@ namespace ASC.Employee.Core.Controllers
{
SecurityContext.DemandPermissions(Tenant, Constants.Action_EditUser);
return QueueWorkerReassign.GetProgressItemStatus(TenantProvider.CurrentTenantID, userId);
return QueueWorkerReassign.GetProgressItemStatus(Tenant.TenantId, userId);
}
[Update(@"reassign/terminate")]
@ -1052,7 +1053,7 @@ namespace ASC.Employee.Core.Controllers
{
SecurityContext.DemandPermissions(Tenant, Constants.Action_EditUser);
QueueWorkerReassign.Terminate(TenantProvider.CurrentTenantID, userId);
QueueWorkerReassign.Terminate(Tenant.TenantId, userId);
}
[Create(@"reassign/start")]
@ -1076,14 +1077,14 @@ namespace ASC.Employee.Core.Controllers
if (toUser.IsVisitor(Tenant) || toUser.Status == EmployeeStatus.Terminated)
throw new ArgumentException("Can not reassign data to user with id = " + toUserId);
return QueueWorkerReassign.Start(TenantProvider.CurrentTenantID, fromUserId, toUserId, SecurityContext.CurrentAccount.ID, deleteProfile);
return QueueWorkerReassign.Start(Tenant.TenantId, fromUserId, toUserId, SecurityContext.CurrentAccount.ID, deleteProfile);
}
private void CheckReassignProccess(IEnumerable<Guid> userIds)
{
foreach (var userId in userIds)
{
var reassignStatus = QueueWorkerReassign.GetProgressItemStatus(TenantProvider.CurrentTenantID, userId);
var reassignStatus = QueueWorkerReassign.GetProgressItemStatus(Tenant.TenantId, userId);
if (reassignStatus == null || reassignStatus.IsCompleted)
continue;
@ -1103,7 +1104,7 @@ namespace ASC.Employee.Core.Controllers
{
SecurityContext.DemandPermissions(Tenant, Constants.Action_EditUser);
return QueueWorkerRemove.GetProgressItemStatus(TenantProvider.CurrentTenantID, userId);
return QueueWorkerRemove.GetProgressItemStatus(Tenant.TenantId, userId);
}
[Update(@"remove/terminate")]
@ -1111,7 +1112,7 @@ namespace ASC.Employee.Core.Controllers
{
SecurityContext.DemandPermissions(Tenant, Constants.Action_EditUser);
QueueWorkerRemove.Terminate(TenantProvider.CurrentTenantID, userId);
QueueWorkerRemove.Terminate(Tenant.TenantId, userId);
}
[Create(@"remove/start")]
@ -1127,7 +1128,7 @@ namespace ASC.Employee.Core.Controllers
if (user.IsOwner(Tenant) || user.IsMe() || user.Status != EmployeeStatus.Terminated)
throw new ArgumentException("Can not delete user with id = " + userId);
return QueueWorkerRemove.Start(TenantProvider.CurrentTenantID, user, SecurityContext.CurrentAccount.ID, true);
return QueueWorkerRemove.Start(Tenant.TenantId, user, SecurityContext.CurrentAccount.ID, true);
}
#endregion

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using ASC.People.Resources;
using ASC.Web.Core;
namespace ASC.People

View File

@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ASC.People.Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class PeopleResource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal PeopleResource() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.People.Resources.PeopleResource", typeof(PeopleResource).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The uploaded file could not be found.
/// </summary>
internal static string ErrorEmptyUploadFileSelected {
get {
return ResourceManager.GetString("ErrorEmptyUploadFileSelected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Image size is too large.
/// </summary>
internal static string ErrorImageSizetLimit {
get {
return ResourceManager.GetString("ErrorImageSizetLimit", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Image file size is too large.
/// </summary>
internal static string ErrorImageWeightLimit {
get {
return ResourceManager.GetString("ErrorImageWeightLimit", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unknown image file type.
/// </summary>
internal static string ErrorUnknownFileImageType {
get {
return ResourceManager.GetString("ErrorUnknownFileImageType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Do the same as a user|Create profiles and groups|Import profiles|Invite users.
/// </summary>
internal static string ProductAdminOpportunities {
get {
return ResourceManager.GetString("ProductAdminOpportunities", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Add new users, invite or import them. Manage users and view their detailed information..
/// </summary>
internal static string ProductDescription {
get {
return ResourceManager.GetString("ProductDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to People.
/// </summary>
internal static string ProductName {
get {
return ResourceManager.GetString("ProductName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to View profiles and groups.
/// </summary>
internal static string ProductUserOpportunities {
get {
return ResourceManager.GetString("ProductUserOpportunities", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Die hochgeladene Datei konnte nicht gefunden werden</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>Das Bild ist zu groß</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>Die Bilddatei ist zu groß</value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>Unbekannter Bilddateityp</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Das gleiche wie der Benutzer tun|Profile und Gruppen erstellen|Profile importieren|Nutzer einladen</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Fügen Sie neue Benutzer hinzu, importieren oder laden Sie diese ein. Verwalten Sie die Benutzer und sehen Sie detaillierte Informationen über sie.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>Personen</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>Profile und Gruppen anschauen</value>
</data>
</root>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Imposible encontrar el archivo subido</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>El tamaño de la imagen es demasiado grande</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>El tamaño del archivo de la imagen es demasiado grande </value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>El tipo de archivo desconocido</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Hacer lo mismo que el usuario|Crear perfiles y grupos|Importar perfiles|Invitar a usuarios</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Añada nuevos usuarios, invítelos o impórtelos. Manéje a los usuarios y vea su información detallada.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>Personas</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>Ver perfiles y grupos</value>
</data>
</root>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Impossible de trouver le fichier chargé</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>La taille de l'image est trop grande</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>La taille du fichier d'image est trop grande</value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>Le type de fichier de l'image est inconnu</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Faire la même chose qu'un utilisateur|Créer des profils et groupes|Importer des profils|Inviter des utilisateurs</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Ajoutez de nouveaux utilisateurs, invitez ou importez-les. Gérez les utilisateurs et visualisez leurs informations détaillées.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>Personnes</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>Afficher les profils et groupes</value>
</data>
</root>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>E' impossibile trovare il file caricato</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>E' stata superata la dimensione immagine massima</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>E' stata superata la dimensione file massima</value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>Tipo file immagine sconosciuto</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Fai lo stesso come un utente|Crea profili e gruppi|Importa profili|Invita utenti</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Aggiungi nuovi utenti, invitali o importali. Gestisci utenti e visualizza le loro informazione dettagliata.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>Persone</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>Vedi profili e gruppi</value>
</data>
</root>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>The uploaded file could not be found</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>Image size is too large</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>Image file size is too large</value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>Unknown image file type</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Do the same as a user|Create profiles and groups|Import profiles|Invite users</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Add new users, invite or import them. Manage users and view their detailed information.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>People</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>View profiles and groups</value>
</data>
</root>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ErrorEmptyUploadFileSelected" xml:space="preserve">
<value>Загружаемый файл не найден</value>
</data>
<data name="ErrorImageSizetLimit" xml:space="preserve">
<value>Размер изображения слишком большой</value>
</data>
<data name="ErrorImageWeightLimit" xml:space="preserve">
<value>Размер файла изображения слишком большой</value>
</data>
<data name="ErrorUnknownFileImageType" xml:space="preserve">
<value>Неизвестный тип файла изображения</value>
</data>
<data name="ProductAdminOpportunities" xml:space="preserve">
<value>Делать то же самое, что и пользователь|Создавать профили и группы|Импортировать профили|Приглашать пользователей</value>
</data>
<data name="ProductDescription" xml:space="preserve">
<value>Добавляйте новых пользователей, приглашайте или импортируйте их. Управляйте пользователями и просматривайте подробную информацию о них.</value>
</data>
<data name="ProductName" xml:space="preserve">
<value>Люди</value>
</data>
<data name="ProductUserOpportunities" xml:space="preserve">
<value>Просматривать профили и группы</value>
</data>
</root>

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
<#@ assembly name="$(MSBuildProjectDirectory)\..\..\..\common\ASC.Core.Common\bin\$(Configuration)\ASC.Core.Common.dll" #>
<#@ include file="$(MSBuildProjectDirectory)\..\..\..\common\ASC.Core.Common\Resources\ResourceGenerator.tt" #>
<#+
string GetNamespace()
{
return "ASC.People";
}
string GetPath()
{
return this.Host.ResolvePath(@"en");
}
#>

View File

@ -1,176 +0,0 @@
{
"AccessRightsSettings": "Zugriffsrechte auf dem Portal",
"Actions": "Aktionen",
"AddButton": "Hinzufügen",
"AddDepartmentDlgTitle": "{!Group} hinzufügen",
"AddImage": "Bild hinzufügen",
"AddMembers": "Mitglieder hinzufügen",
"BlockedMessage": "Deaktiviert",
"CancelButton": "Abbrechen",
"ChangeStatus": "Status ändern",
"ChangeStatusButton": "Benutzerstatus ändern",
"ChangeStatusDialogConstraint": "Aktualisieren Sie Ihren Tarifplan und wiederholen Sie die Operation, sonst wird der Status der anderen Benutzer nicht geändert.",
"ChangeStatusDialogHeader": "Benutzerstatus ändern",
"ChangeStatusDialogRestriction": "Sie können den Status für den Portalbesitzer und sich selbst nicht ändern",
"ChangeStatusDialogToActive": "Die Benutzer mit dem Status 'deaktiviert' werden aktiviert.",
"ChangeStatusDialogToTerminate": "Die Benutzer mit dem Status 'aktiv' werden deaktiviert.",
"ChangeType": "Typ ändern",
"ChangeTypeDialogConstraint": "Aktualisieren Sie Ihren Tarifplan und wiederholen Sie die Operation, sonst wird der Typ der anderen Benutzer nicht geändert.",
"ChangeTypeDialogHeader": "Benutzertyp ändern",
"ChangeTypeDialogRestriction": "Sie können den Typ für die Portaladministratoren und sich selbst nicht ändern",
"ChangeTypeDialogToGuest": "Die Benutzer mit dem Typ 'Benutzer' werden auf den Typ 'Gast' verschoben",
"ChangeTypeDialogToUser": "Die Benutzer mit dem Typ 'Gast' werden auf den Typ 'Benutzer' verschoben",
"ChooseUser": "Benutzer wählen",
"ClearButton": "Filter zurücksetzen",
"Confirmation": "Bestätigung",
"CreateNewProfile": "Neuen Benutzer erstellen",
"DeleteBtnHint": "Nur Benutzer oder Gäste mit dem Status 'Deaktiviert' können gelöscht werden",
"DeleteButton": "Löschen",
"DeleteProfileAfterReassignment": "Profil löschen, wenn die Neuzuordnung abgeschlossen ist",
"DeleteUserProfiles": "Löschung der Benutzer aus dem Portal",
"DeleteUsersDataConfirmation": "Persönliche Dokumente dieser Benutzer, die für andere verfügbar sind, werden gelöscht. Um dies zu vermeiden, müssen Sie den Datentransfer vor dem Löschen starten.",
"DeleteUsersDescription": "Die gewünschten deaktivierten Benutzer werden aus dem Portal gelöscht. Bitte beachten Sie, dass diese Aktion nicht widerrufen werden kann. Sie können die Benutzer nicht löschen, falls sie den Status 'Aktiv' oder 'Ausstehend' haben, sie müssen erst deaktiviert werden. ",
"DeleteUsersDescriptionText": "Die ausgewählten deaktivierten Benutzer werden vom Portal gelöscht.",
"DepartmentMaster": "{!Head}",
"DeselectAll": "Markierung aufheben",
"DisableUserButton": "Deaktivieren",
"DisableUserHelp": "Der {!User} wird nicht mehr in der Liste mit aktiven {!Users}n angezeigt",
"EditButton": "Bearbeiten",
"EditImage": "Bild bearbeiten",
"Email": "E-Mail-Adresse",
"EnableUserButton": "Aktivieren",
"EnableUserHelp": "Der {!User} wird als aktiv wieder angezeigt",
"ErrorEmptyName": "Geben Sie einen Namen ein",
"ErrorEmptyUploadFileSelected": "Die hochgeladene Datei konnte nicht gefunden werden",
"ErrorImageSizetLimit": "Das Bild ist zu groß",
"ErrorImageWeightLimit": "Die Bilddatei ist zu groß",
"ErrorUnknownFileImageType": "Unbekannter Bilddateityp",
"ExampleValues": "Beispielwerte",
"FieldsInFile": "Felder in der Datei",
"FieldsOnPortal": "Felder im ONLYOFFICE-Portal",
"FirstName": "Vorname",
"Hide": "Ausblenden",
"HideSelectedUserList": "Liste der gewählten Benutzer ausblenden",
"ImportClear": "Leeren",
"ImportColumn": "Spalte",
"ImportDelimiterDQ": "Doppeltes Anführungszeichen",
"ImportDelimiterSQ": "Einfaches Anführungszeichen",
"ImportEncodingASCII": "ASCII",
"ImportEncodingCP866": "CP-866",
"ImportEncodingKOI8R": "KOI8-R",
"ImportEncodingUTF8": "UTF-8",
"ImportEncodingWindows1251": "Windows1251",
"ImportFromFile": "Aus Datei",
"ImportFromGoogle": "Google",
"ImportFromYahoo": "Yahoo",
"ImportPeople": "Personen importieren",
"ImportSeparatorColon": "Doppelpunkt",
"ImportSeparatorComma": "Komma",
"ImportSeparatorSemicolon": "Semikolon",
"ImportSeparatorSpace": "Leerzeichen",
"ImportSeparatorTab": "Tabulator",
"ImportWizardFirstStep": "Kontakte importieren",
"ImportWizardFourthStep": "Dem Portal hinzufügen",
"ImportWizardSecondStep": "Compliance-System einrichten",
"ImportWizardThirdStep": "Kontakte bearbeiten",
"InviteLink": "Einladungslink",
"LastName": "Nachname",
"LblActive": "Aktiv",
"LblByName": "Name",
"LblByType": "Typ",
"LblCancelButton": "Abbrechen",
"LblChangeEmail": "E-Mail-Adresse ändern",
"LblChangePassword": "Kennwort ändern",
"LblCreateNew": "Erstellen",
"LblDeleteProfile": "Profil löschen",
"LblEdit": "Bearbeiten",
"LblImportAccounts": "Konten importieren",
"LblMobilePhone": "Hauptmobiltelefon",
"LblOKButton": "OK",
"LblOther": "Sonstiges",
"LblPassword": "Kennwort",
"LblPending": "Ausstehend",
"LblReassignData": "Daten erneut zuweisen",
"LblRemoveData": "Persönliche Daten löschen",
"LblResendInvites": "Einladungen erneut senden",
"LblSendActivation": "Link zum Aktivieren erneut senden",
"LblSendEmail": "E-Mail senden",
"LblSendMessage": "Nachricht senden",
"LblStatus": "Status",
"LblSubscriptions": "Benachrichtigungen",
"LblTerminated": "Deaktiviert",
"LblTips": "QuickInfo",
"MainEmail": "Haupt-E-Mail-Adresse",
"Members": "Mitglieder",
"NoSameValuesOptions": "Felder im Portal können nicht dieselben Werte haben!",
"NotFoundDescription": "In dieser Sektion können keine Personen nach Ihren Filterkriterien angezeigt werden... Bitte wählen Sie andere Filteroptionen oder leeren Sie den Filter, um alle Personen in dieser Sektion zu sehen.",
"NotFoundTitle": "Keine Ergebnisse nach Ihren Filterkriterien gefunden ",
"NotImport": "Nicht importieren",
"OnTop": "Oben",
"ProductAdminOpportunities": "Das gleiche wie der Benutzer tun|Profile und Gruppen erstellen|Profile importieren|Nutzer einladen",
"ProductDescription": "Fügen Sie neue Benutzer hinzu, importieren oder laden Sie diese ein. Verwalten Sie die Benutzer und sehen Sie detaillierte Informationen über sie.",
"ProductName": "Personen",
"ProductUserOpportunities": "Profile und Gruppen anschauen",
"ReadAboutNonProfit": "Oder {0}lesen Sie über die nicht-kommerzielle Nutzung{1}.",
"ReassignAbortButton": "Übertragung abbrеchen",
"ReassignAbortToastrMsg": "Datenübertragung ist abgebrochen",
"ReassignButton": "Neu zuweisen",
"ReassignCrmModule": "CRM",
"ReassignDocumentsModule": "Dokumente",
"ReassignErrorToastrMsg": "Die Datenübertragung wurde aufgrund eines Serverfehlers unterbrochen",
"ReassignMailModule": "Email",
"ReassignmentData": "Neuzuweisung von Daten",
"ReassignProjectsModule": "Projekte",
"ReassignRestartButton": "Starten Sie die Übertragung erneut",
"ReassignsProgressNotifyInfo": "Sie können diese Seite schließen. Wenn der Vorgang abgeschlossen ist, wird der Administrator, der ihn ausführt, per E-Mail benachrichtigt.",
"ReassignsProgressText": "Der Prozess der Datenübertragung wird gestartet, er kann einige Zeit dauern. {0} Sie können diese Seite schließen. Wenn der Vorgang abgeschlossen ist, wird der Administrator, der ihn ausführt, per E-Mail benachrichtigt.",
"ReassignsProgressUserInfo": "Der Prozess der Neuzuordnung der Daten von Benutzer {0} zu Benutzer {1} wurde gestartet. Dies kann einige Zeit dauern.",
"ReassignsReadMore": "Mehr zur Datenübertragung",
"ReassignStatusAborted": "Unterbrochen, einige Daten könnten übertragen werden",
"ReassignStatusError": "Server-Fehler",
"ReassignStatusFinished": "Alle Daten werden übertragen",
"ReassignStatusNotStarted": "Daten wurden nicht übertragen",
"ReassignStatusQueued": "In Warteschlange",
"ReassignStatusStarted": "Gestart",
"ReassignsToUser": "Mitarbeiter, an den die Daten übermittelt werden -",
"ReassignsTransferedListHdr": "Werden überwiesen:",
"ReassignsTransferedListItem1": "Allgemeine und persönliche Dokumente, die anderen Portalbenutzern zur Verfügung stehen;",
"ReassignsTransferedListItem2": "Offene Projekte, Meilensteine und Aufgaben;",
"ReassignsTransferedListItem3": "Kontakte, offene Aufgaben, nicht geschlossene Verkaufschancen und CRM-Veranstaltungen;",
"ReassignTalkModule": "Chat",
"RemovingAbortButton": "Entfernen abbrechen",
"RemovingAbortToastrMsg": "Datenlöschung ist abgebrochen",
"RemovingData": "Löschen von persönlichen Daten",
"RemovingErrorToastrMsg": "Die Datenlöschung wurde aufgrund eines Serverfehlers unterbrochen",
"RemovingListHdr": "Werden entfernt:",
"RemovingListItem1": "Alle persönliche Dokumente;",
"RemovingListItem2": "CRM Berichtsdateien;",
"RemovingListItem3": "Alle E-Mails und angehängte Dateien;",
"RemovingListItem4": "Dateien aus Chat angehängt;",
"RemovingProgressUserInfo": "Der Prozess zum Löschen personenbezogener Daten für den Benutzer {0} kann gestartet werden. Dies kann einige Zeit in Anspruch nehmen.",
"RemovingReadMore": "Mehr zum Löschen der persönlichen Daten",
"RemovingRestartButton": "Starten Sie das Entfernen erneut",
"RemovingStatusAborted": "Unterbrochen, einige Daten könnten gelöscht werden",
"RemovingStatusFinished": "Alle Daten werden gelöscht",
"RemovingStatusNotStarted": "Daten wurden nicht gelöscht",
"ResendInviteDialogAfterActivation": "Nachdem die Benutzer die Einladung zum Portal bestätigt haben, wird ihr Status auf 'aktiv' ändern",
"ResendInviteDialogHeader": "Einladungen erneut senden",
"ResendInviteDialogTargetUsers": "Die Einladung zum Portal wird an die gewählten, nicht deaktivierten Benutzer mit dem Status 'ausstehend' noch einmal versandt. ",
"SaveButton": "Speichern",
"SelectAll": "Alle markieren",
"SelectedCount": "{0} ausgewählt",
"Settings": "Einstellungen",
"Show": "Einblenden",
"ShowOnPage": "Auf der Seite anzeigen",
"ShowSelectedUserList": "Liste der gewählten Benutzer sehen",
"SocialProfiles": "Soziale Profile",
"SuccessfullyDeleteUserInfoMessage": "Der Benutzer wurde erfolgreich gelöscht",
"SuccessfullySentNotificationDeleteUserInfoMessage": "Die Hinweise zum Löschen Ihres Profils werden an Ihre E-Mail-Adresse gesendet",
"TariffActiveUserLimit": "Ihr aktueller Zahlungsplan erlaubt Ihnen {0}{1} aktive Benutzer{2} hinzuzufügen.",
"TerminateButton": "Beenden",
"Title": "Titel",
"TitleThumbnailPhoto": "Vorschaubilder ändern",
"TotalCount": "Gesamtanzahl",
"WaitingForConfirmation": "In Erwartung der Bestätigung",
"WriteButton": "Brief schreiben"
}

View File

@ -1,176 +0,0 @@
{
"AccessRightsSettings": "Portal Access Rights",
"Actions": "Actions",
"AddButton": "Add",
"AddDepartmentDlgTitle": "Add {!group}",
"AddImage": "Add Image",
"AddMembers": "Add members",
"BlockedMessage": "Disabled",
"CancelButton": "Cancel",
"ChangeStatus": "Change status",
"ChangeStatusButton": "Change user status",
"ChangeStatusDialogConstraint": "If this number exceeds the current pricing plan you will need to upgrade your plan and repeat the operation or other users status will not be changed.",
"ChangeStatusDialogHeader": "Change user status",
"ChangeStatusDialogRestriction": "You cannot change the status for portal owner and for yourself",
"ChangeStatusDialogToActive": "The users with the 'Disabled' status will be enabled.",
"ChangeStatusDialogToTerminate": "The users with the 'Active' status will be disabled.",
"ChangeType": "Change type",
"ChangeTypeDialogConstraint": "Upgrade your plan and repeat the operation or other users type will not be changed.",
"ChangeTypeDialogHeader": "Change user type",
"ChangeTypeDialogRestriction": "You cannot change the type for portal administrators and for yourself",
"ChangeTypeDialogToGuest": "Users with the '{!User}' type will be moved to '{!Guest}' type",
"ChangeTypeDialogToUser": "Users with the '{!Guest}' type will be moved to '{!User}' type",
"ChooseUser": "Choose user",
"ClearButton": "Reset filter",
"Confirmation": "Confirmation",
"CreateNewProfile": "Create New User",
"DeleteBtnHint": "Only users or guests with the 'Disabled' status can be deleted",
"DeleteButton": "Delete",
"DeleteProfileAfterReassignment": "Delete profile when reassignment is finished",
"DeleteUserProfiles": "Delete the users from portal",
"DeleteUsersDataConfirmation": "Personal documents of these users which are available to others will be deleted. To avoid this, you must start the data transfer process before deleting.",
"DeleteUsersDescription": "The selected disabled users will be deleted from the portal. Please note that this action cannot be undone.\r\nYou cannot delete the users if they have 'Active' or 'Pending' status, they need to be disabled first.",
"DeleteUsersDescriptionText": "The selected disabled users will be deleted from the portal.",
"DepartmentMaster": "{!Head}",
"DeselectAll": "Deselect all",
"DisableUserButton": "Disable",
"DisableUserHelp": "The {!user} will not be displayed in the list of active {!users}",
"EditButton": "Edit",
"EditImage": "Edit Image",
"Email": "Email",
"EnableUserButton": "Enable",
"EnableUserHelp": "The {!user} will be displayed as active again",
"ErrorEmptyName": "Enter a name",
"ErrorEmptyUploadFileSelected": "The uploaded file could not be found",
"ErrorImageSizetLimit": "Image size is too large",
"ErrorImageWeightLimit": "Image file size is too large",
"ErrorUnknownFileImageType": "Unknown image file type",
"ExampleValues": "Example values",
"FieldsInFile": "Fields in file",
"FieldsOnPortal": "Fields on the ONLYOFFICE portal",
"FirstName": "First Name",
"Hide": "Hide",
"HideSelectedUserList": "Hide the selected users list",
"ImportClear": "Clear",
"ImportColumn": "Column",
"ImportDelimiterDQ": "Double quote",
"ImportDelimiterSQ": "Single quote",
"ImportEncodingASCII": "ASCII",
"ImportEncodingCP866": "CP-866",
"ImportEncodingKOI8R": "KOI8-R",
"ImportEncodingUTF8": "UTF-8",
"ImportEncodingWindows1251": "Windows1251",
"ImportFromFile": "From File",
"ImportFromGoogle": "Google",
"ImportFromYahoo": "Yahoo",
"ImportPeople": "Import People",
"ImportSeparatorColon": "Colon",
"ImportSeparatorComma": "Comma",
"ImportSeparatorSemicolon": "Semicolon",
"ImportSeparatorSpace": "Space",
"ImportSeparatorTab": "Tab",
"ImportWizardFirstStep": "Import contacts",
"ImportWizardFourthStep": "Add to portal",
"ImportWizardSecondStep": "Setting up compliance",
"ImportWizardThirdStep": "Edit Contacts",
"InviteLink": "Invitation Link",
"LastName": "Last Name",
"LblActive": "Active",
"LblByName": "Name",
"LblByType": "Type",
"LblCancelButton": "Cancel",
"LblChangeEmail": "Change email",
"LblChangePassword": "Change password",
"LblCreateNew": "Create",
"LblDeleteProfile": "Delete profile",
"LblEdit": "Edit",
"LblImportAccounts": "Import accounts",
"LblMobilePhone": "Primary Mobile Phone",
"LblOKButton": "OK",
"LblOther": "Other",
"LblPassword": "Password",
"LblPending": "Pending",
"LblReassignData": "Reassign data",
"LblRemoveData": "Delete personal data",
"LblResendInvites": "Send invitations once again",
"LblSendActivation": "Send activation link once again",
"LblSendEmail": "Send email",
"LblSendMessage": "Send message",
"LblStatus": "Status",
"LblSubscriptions": "Subscriptions",
"LblTerminated": "Disabled",
"LblTips": "Tooltips",
"MainEmail": "Main Email",
"Members": "Members",
"NoSameValuesOptions": "Fields on the portal cannot have the same values!",
"NotFoundDescription": "No people matching your filter can be displayed in this section. Please select other filter options or clear filter to view all the people in this section.",
"NotFoundTitle": "No results matching your search could be found",
"NotImport": "Not import",
"OnTop": "On top",
"ProductAdminOpportunities": "Do the same as a user|Create profiles and groups|Import profiles|Invite users",
"ProductDescription": "Add new users, invite or import them. Manage users and view their detailed information.",
"ProductName": "People",
"ProductUserOpportunities": "View profiles and groups",
"ReadAboutNonProfit": "Or {0}read about non-profit usage{1}.",
"ReassignAbortButton": "Abort transfer",
"ReassignAbortToastrMsg": "Data transfer aborted",
"ReassignButton": "Reassign",
"ReassignCrmModule": "CRM",
"ReassignDocumentsModule": "Documents",
"ReassignErrorToastrMsg": "Data transfer interrupted due to a server error",
"ReassignMailModule": "Mail",
"ReassignmentData": "Data reassignment",
"ReassignProjectsModule": "Projects",
"ReassignRestartButton": "Start transfer again",
"ReassignsProgressNotifyInfo": "You can close this page. When the process is completed, the administrator who runs it will be notified by mail.",
"ReassignsProgressText": "The process of data transfer is started, it can take a considerable time.{0}You can close this page. When the process is completed, the administrator who runs it will be notified by mail.",
"ReassignsProgressUserInfo": "The process of reassignment data from user {0} to user {1} started, it can take a considerable time.",
"ReassignsReadMore": "More about data transfer",
"ReassignStatusAborted": "Interrupted, some data could be transferred",
"ReassignStatusError": "Server error",
"ReassignStatusFinished": "All data transferred",
"ReassignStatusNotStarted": "Data was not transferred",
"ReassignStatusQueued": "Queued",
"ReassignStatusStarted": "Started",
"ReassignsToUser": "Employee to whom the data will be transferred -",
"ReassignsTransferedListHdr": "Will be transferred:",
"ReassignsTransferedListItem1": "General and personal documents available to other portal users;",
"ReassignsTransferedListItem2": "Open projects, milestones and tasks;",
"ReassignsTransferedListItem3": "Contacts, open tasks, not closed opportunities and CRM cases;",
"ReassignTalkModule": "Talk",
"RemovingAbortButton": "Abort removal",
"RemovingAbortToastrMsg": "Data deletion aborted",
"RemovingData": "Deleting personal data",
"RemovingErrorToastrMsg": "Data deletion interrupted due to a server error",
"RemovingListHdr": "Will be removed:",
"RemovingListItem1": "All personal documents;",
"RemovingListItem2": "CRM report files;",
"RemovingListItem3": "All emails and attached files;",
"RemovingListItem4": "Attached from Talk files;",
"RemovingProgressUserInfo": "The process of deleting personal data for user {0} started, it can take a considerable time.",
"RemovingReadMore": "More about deleting the personal data",
"RemovingRestartButton": "Start removing again",
"RemovingStatusAborted": "Interrupted, some data could be deleted",
"RemovingStatusFinished": "All data deleted",
"RemovingStatusNotStarted": "Data was not deleted",
"ResendInviteDialogAfterActivation": "After the users confirm the invitation to the portal their status will change to 'Active'",
"ResendInviteDialogHeader": "Send invitation once again",
"ResendInviteDialogTargetUsers": "The invitation to the portal will be sent once again to the selected users with the 'Pending' status who are not disabled.",
"SaveButton": "Save",
"SelectAll": "Select all",
"SelectedCount": "{0} selected",
"Settings": "Settings",
"Show": "Show",
"ShowOnPage": "Show on page",
"ShowSelectedUserList": "View the selected users list",
"SocialProfiles": "Social Profiles",
"SuccessfullyDeleteUserInfoMessage": "User has been successfully deleted",
"SuccessfullySentNotificationDeleteUserInfoMessage": "The instructions for your profile deletion have been sent to email address",
"TariffActiveUserLimit": "Your current pricing plan allows you to add {0}{1} active users{2}.",
"TerminateButton": "Terminate",
"Title": "Title",
"TitleThumbnailPhoto": "Change Thumbnails",
"TotalCount": "Total count",
"WaitingForConfirmation": "Waiting for confirmation",
"WriteButton": "Write Letter"
}

View File

@ -1,176 +0,0 @@
{
"AccessRightsSettings": "Droits d'accès sur le portail",
"Actions": "Actions",
"AddButton": "Ajouter",
"AddDepartmentDlgTitle": "Ajouter {!group}",
"AddImage": "Ajouter image",
"AddMembers": "Ajouter membres",
"BlockedMessage": "Désactivé",
"CancelButton": "Annuler",
"ChangeStatus": "Changer statut",
"ChangeStatusButton": "Modifier le statut",
"ChangeStatusDialogConstraint": "Si ce nombre dépasse le plan de tarification actuel, vous devez mettre à jour votre plan et répétez l'opération sinon le statut des autres utilisateurs ne sera pas modifié.",
"ChangeStatusDialogHeader": "Modifier le statut de l'utilisateur",
"ChangeStatusDialogRestriction": "Vous ne pouvez pas changer le statut de propriétaire du portail et votre propre statut",
"ChangeStatusDialogToActive": "Les utilisateurs avec le statut 'Désactivé' seront activés.",
"ChangeStatusDialogToTerminate": "Les utilisateurs avec le statut 'Actif' seront désactivés.",
"ChangeType": "Modifier le type",
"ChangeTypeDialogConstraint": "Actualisez votre plan et répétez l'opération sinon le type des autres utilisateurs ne sera pas modifié.",
"ChangeTypeDialogHeader": "Changer le type d'utilisateur",
"ChangeTypeDialogRestriction": "Vous ne pouvez pas changer votre type ou le type de propriétaire du portail",
"ChangeTypeDialogToGuest": "Les utilisateurs du type '{!User}' seront déplacés dans le type '{!Guest}'",
"ChangeTypeDialogToUser": "Les utilisateurs du type '{!Guest}' seront déplacés dans le type '{!User}'",
"ChooseUser": "Choisir l'utilisateur",
"ClearButton": "Réinitialiser le filtre",
"Confirmation": "Confirmation",
"CreateNewProfile": "Créer un nouvel utilisateur",
"DeleteBtnHint": "Ce ne sont que les utilisateurs et les invités avec le statut 'Desactivé' qui peuvent être supprimés",
"DeleteButton": "Supprimer",
"DeleteProfileAfterReassignment": "Supprimer le profile lorsque réaffectation est finie",
"DeleteUserProfiles": "Supprimer l'utilisateur du portail",
"DeleteUsersDataConfirmation": "Les documents personnels de ces utilisateurs qui sont patagés avec d'autres seront supprimés. Pour éviter cela, vous devez démarrer le processus de transfert de données avant la suppression.",
"DeleteUsersDescription": "Les utilisateurs désactivés sélectionnés seront supprimés du portail. Il est à noter que cette action ne peut pas être annulée. Vous ne pouvez pas supprimer des utilisateurs qui ont des statuts 'Actif' ou 'En attente', tout d'abord il faut les désactiver.",
"DeleteUsersDescriptionText": "Les utilisateurs handicapés sélectionnés seront supprimés du portail.",
"DepartmentMaster": "{!Head}",
"DeselectAll": "Désélectionner tout",
"DisableUserButton": "Désactiver",
"DisableUserHelp": "{!User} ne sera pas affiché dans la liste des {!users} actifs",
"EditButton": "Modifier",
"EditImage": "Modifier image",
"Email": "Email",
"EnableUserButton": "Activer ",
"EnableUserHelp": "{!User} sera affiché de nouveau comme actif ",
"ErrorEmptyName": "Entrez un nom",
"ErrorEmptyUploadFileSelected": "Impossible de trouver le fichier chargé",
"ErrorImageSizetLimit": "La taille de l'image est trop grande",
"ErrorImageWeightLimit": "La taille du fichier d'image est trop grande",
"ErrorUnknownFileImageType": "Le type de fichier de l'image est inconnu",
"ExampleValues": "Valeurs d'example",
"FieldsInFile": "Chapms dans le fichier",
"FieldsOnPortal": "Champs sur le portail ONLYOFFICE",
"FirstName": "Prénom",
"Hide": "Cacher",
"HideSelectedUserList": "Cacher la liste des utilisateurs sélectionnés",
"ImportClear": "Effacer",
"ImportColumn": "Colonne",
"ImportDelimiterDQ": "Guillemets doubles",
"ImportDelimiterSQ": "Guillemet simple",
"ImportEncodingASCII": "ASCII",
"ImportEncodingCP866": "CP-866",
"ImportEncodingKOI8R": "KOI8-R",
"ImportEncodingUTF8": "UTF-8",
"ImportEncodingWindows1251": "Windows1251",
"ImportFromFile": "Depuis un fichier",
"ImportFromGoogle": "Google",
"ImportFromYahoo": "Yahoo",
"ImportPeople": "Importer personnes",
"ImportSeparatorColon": "Deux-points",
"ImportSeparatorComma": "Virgule",
"ImportSeparatorSemicolon": "Point-virgule",
"ImportSeparatorSpace": "Espace",
"ImportSeparatorTab": "Tabulation",
"ImportWizardFirstStep": "Importer les contacts",
"ImportWizardFourthStep": "Ajouter au portail",
"ImportWizardSecondStep": "Mise en place de conformité",
"ImportWizardThirdStep": "Modifier Contacts",
"InviteLink": "Lien d'invitation",
"LastName": "Nom",
"LblActive": "Actif",
"LblByName": "Nom",
"LblByType": "Type",
"LblCancelButton": "Annuler",
"LblChangeEmail": "Modifier l'émail",
"LblChangePassword": "Changer le mot de passe",
"LblCreateNew": "Créer",
"LblDeleteProfile": "Supprimer le profil",
"LblEdit": "Modifier",
"LblImportAccounts": "Importer des comptes",
"LblMobilePhone": "Numéro de téléphone principale",
"LblOKButton": "OK",
"LblOther": "Autre",
"LblPassword": "Mot de passe",
"LblPending": "En attente",
"LblReassignData": "Réaffecter des données",
"LblRemoveData": "Supprimer les données personnelles",
"LblResendInvites": "Renvoyer les invitations",
"LblSendActivation": "Envoyer un lien d'activation encore une fois",
"LblSendEmail": "Envoyer message",
"LblSendMessage": "Envoyer message",
"LblStatus": "Statut",
"LblSubscriptions": "Abonnements",
"LblTerminated": "Désactivé",
"LblTips": "Info-bulles",
"MainEmail": "Email principale",
"Members": "Membres",
"NoSameValuesOptions": "Champs sur le portail ne peuvent pas avoir les mêmes valeurs!",
"NotFoundDescription": "Aucune personne CRM correspondant à votre filtre peut être affichée dans cette section. Sélectionnez d'autres options de filtre ou effacez le filtre pour afficher toutes les personnes dans cette section.",
"NotFoundTitle": "Aucun résultat correspondant à vos critères n'a pu être trouvé",
"NotImport": "N'importer pas",
"OnTop": "En haut",
"ProductAdminOpportunities": "Faire la même chose qu'un utilisateur|Créer des profils et groupes|Importer des profils|Inviter des utilisateurs",
"ProductDescription": "Ajoutez de nouveaux utilisateurs, invitez ou importez-les. Gérez les utilisateurs et visualisez leurs informations détaillées.",
"ProductName": "Personnes",
"ProductUserOpportunities": "Afficher les profils et groupes",
"ReadAboutNonProfit": "Ou {0}lisez sur l'utilisation à but non lucratif{1}.",
"ReassignAbortButton": "Annuler le transfert",
"ReassignAbortToastrMsg": "Transfert de données annulé",
"ReassignButton": "Réaffecter",
"ReassignCrmModule": "CRM",
"ReassignDocumentsModule": "Documents",
"ReassignErrorToastrMsg": "Transfert de données interrompu dû à une erreur de serveur",
"ReassignMailModule": "Mail",
"ReassignmentData": "Réattribution de données",
"ReassignProjectsModule": "Projets",
"ReassignRestartButton": "Recommencer le transfert",
"ReassignsProgressNotifyInfo": "Vous pouvez fermer cette page. Lorsque le processus sera terminé, l'administrateur qui l'exécute sera averti par mail.",
"ReassignsProgressText": "Le processus de transfert de données est démarré, cela peut prendre beaucoup de temps.{0}Vous pouvez fermer cette page. Lorsque le processus sera terminé, l'administrateur qui l'exécute sera averti par mail.",
"ReassignsProgressUserInfo": "Le processus de réaffectation des données de l'utilisateur {0} à l'utilisateur {1} a commencé, cela peut prendre beaucoup de temps.",
"ReassignsReadMore": "En savoir plus sur le transfert de données",
"ReassignStatusAborted": "Interrompu, certaines données pourraient être transférées",
"ReassignStatusError": "Erreur de serveur",
"ReassignStatusFinished": "Toutes les données transférées",
"ReassignStatusNotStarted": "Les données n'ont pas été transférées",
"ReassignStatusQueued": "En file d'attente",
"ReassignStatusStarted": "Démarrer",
"ReassignsToUser": "Employé à qui les données seront transférées -",
"ReassignsTransferedListHdr": "Sera transféré:",
"ReassignsTransferedListItem1": "Documents généraux et personnels disponibles pour les autres utilisateurs du portail;",
"ReassignsTransferedListItem2": "Projets ouverts, jalons et tâches;",
"ReassignsTransferedListItem3": "Contacts, tâches ouvertes, opportunités non fermées et cas de CRM;",
"ReassignTalkModule": "Chat",
"RemovingAbortButton": "Annuler la suppression",
"RemovingAbortToastrMsg": "Suppression de données annulée",
"RemovingData": "Suppression de données personnelles",
"RemovingErrorToastrMsg": "Suppression de données interrompue en raison d'une erreur de serveur",
"RemovingListHdr": "Sera suprimé:",
"RemovingListItem1": "Tous les documents personnels;",
"RemovingListItem2": "Fichiers de rapport CRM;",
"RemovingListItem3": "Tous les e-mails et fichiers joints;",
"RemovingListItem4": "Fichiers joints à partir de Talk;",
"RemovingProgressUserInfo": "Le processus de suppression des données personnelles pour l'utilisateur {0} a commencé, cela peut prendre beaucoup de temps.",
"RemovingReadMore": "En savoir plus sur la suppression des données personnelles",
"RemovingRestartButton": "Commencez à supprimer à nouveau",
"RemovingStatusAborted": "Interrompu, certaines données pourraient être supprimées",
"RemovingStatusFinished": "Toutes les données supprimées",
"RemovingStatusNotStarted": "Les données n'ont pas été supprimées",
"ResendInviteDialogAfterActivation": "Après que les utilisateurs confirment l'invitation sur le portail leurs statuts deviennent 'Actif'",
"ResendInviteDialogHeader": "Renvoyer l'invitation",
"ResendInviteDialogTargetUsers": "L'invitation sur le portail sera renvoyée aux utilisateurs sélectionnés avec le statut 'En attente' qui ne sont pas désactivés.",
"SaveButton": "Enregistrer",
"SelectAll": "Sélectionner tout",
"SelectedCount": "{0} sélectionné",
"Settings": "Paramètres",
"Show": "Afficher",
"ShowOnPage": "Afficher sur la page",
"ShowSelectedUserList": "Afficher la liste des utilisateurs sélectionnés",
"SocialProfiles": "Profils sociaux",
"SuccessfullyDeleteUserInfoMessage": "L'utilisateur a été supprimé avec succès",
"SuccessfullySentNotificationDeleteUserInfoMessage": "Les instructions sur la suppression de votre profil sont été envoyées à l'adresse email",
"TariffActiveUserLimit": "Le plan tarifaire actuel permet d'ajouter les {0}{1}utilisateurs actifs{2}.",
"TerminateButton": "Terminer",
"Title": "Titre",
"TitleThumbnailPhoto": "Modifier vignettes",
"TotalCount": "Nombre total",
"WaitingForConfirmation": "En attente de confirmation",
"WriteButton": "Ecrire un message"
}

View File

@ -1,176 +0,0 @@
{
"AccessRightsSettings": "Права доступа на портале",
"Actions": "Действия",
"AddButton": "Добавить",
"AddDepartmentDlgTitle": "Добавить группу",
"AddImage": "Добавить изображение",
"AddMembers": "Добавить участников",
"BlockedMessage": "Заблокирован",
"CancelButton": "Отмена",
"ChangeStatus": "Изменить статус",
"ChangeStatusButton": "Изменить статус",
"ChangeStatusDialogConstraint": "Если это число превышает текущий тарифный план, вам потребуется повысить тарифный план и повторить операцию, иначе статус остальных пользователей не изменится.",
"ChangeStatusDialogHeader": "Изменение статуса пользователя",
"ChangeStatusDialogRestriction": "Вы не можете изменить статус владельца портала и свой собственный статус",
"ChangeStatusDialogToActive": "Пользователи со статусом 'Заблокирован' будут разблокированы.",
"ChangeStatusDialogToTerminate": "Пользователи со статусом 'Активный' будут заблокированы.",
"ChangeType": "Изменить тип",
"ChangeTypeDialogConstraint": "Повысьте тарифный план и повторите операцию, иначе тип остальных пользователей не изменится.",
"ChangeTypeDialogHeader": "Изменение типа пользователя",
"ChangeTypeDialogRestriction": "Вы не можете изменить тип для администраторов портала и для самого себя",
"ChangeTypeDialogToGuest": "Пользователи с типом '{!User}' будут переведены в тип '{!Guest}'",
"ChangeTypeDialogToUser": "Пользователи с типом '{!Guest}' будут переведены в тип '{!User}'",
"ChooseUser": "Выбрать пользователя",
"ClearButton": "Сбросить фильтр",
"Confirmation": "Подтверждение",
"CreateNewProfile": "Создание нового пользователя",
"DeleteBtnHint": "Удалить можно только пользователей или гостей со статусом 'Заблокирован'",
"DeleteButton": "Удалить",
"DeleteProfileAfterReassignment": "Удалить профиль после завершения передачи данных",
"DeleteUserProfiles": "Удаление пользователей с портала",
"DeleteUsersDataConfirmation": "Будут удалены личные документы этих пользователей, доступные для других. Чтобы избежать этого, нужно перед удалением запустить процесс передачи данных.",
"DeleteUsersDescription": "Выбранные заблокированные пользователи будут удалены с портала. Пожалуйста, обратите внимание на то, что это действие нельзя отменить.\nПользователей со статусом 'Активный' или 'Ожидание' удалить нельзя, сначала их надо заблокировать.",
"DeleteUsersDescriptionText": "Выбранные заблокированные пользователи будут удалены с портала.",
"DepartmentMaster": "{!Head}",
"DeselectAll": "Отменить выбор",
"DisableUserButton": "Заблокировать",
"DisableUserHelp": "{!User} не будет отображаться в списке активных",
"EditButton": "Редактировать",
"EditImage": "Изменить изображение",
"Email": "Email",
"EnableUserButton": "Разблокировать",
"EnableUserHelp": "{!User} снова перейдет в статус активных",
"ErrorEmptyName": "Введите название",
"ErrorEmptyUploadFileSelected": "Загружаемый файл не найден",
"ErrorImageSizetLimit": "Размер изображения слишком большой",
"ErrorImageWeightLimit": "Размер файла изображения слишком большой",
"ErrorUnknownFileImageType": "Неизвестный тип файла изображения",
"ExampleValues": "Примеры значений",
"FieldsInFile": "Поля в файле",
"FieldsOnPortal": "Поля на портале ONLYOFFICE",
"FirstName": "Имя",
"Hide": "Скрыть",
"HideSelectedUserList": "Скрыть список выбранных пользователей",
"ImportClear": "Очистить",
"ImportColumn": "Столбец",
"ImportDelimiterDQ": "Двойная кавычка",
"ImportDelimiterSQ": "Одинарная кавычка",
"ImportEncodingASCII": "ASCII",
"ImportEncodingCP866": "CP-866",
"ImportEncodingKOI8R": "KOI8-R",
"ImportEncodingUTF8": "UTF-8",
"ImportEncodingWindows1251": "Windows1251",
"ImportFromFile": "Из файла",
"ImportFromGoogle": "Google",
"ImportFromYahoo": "Yahoo",
"ImportPeople": "Импортировать людей",
"ImportSeparatorColon": "Двоеточие",
"ImportSeparatorComma": "Запятая",
"ImportSeparatorSemicolon": "Точка с запятой",
"ImportSeparatorSpace": "Пробел",
"ImportSeparatorTab": "Табуляция",
"ImportWizardFirstStep": "Импорт контактов",
"ImportWizardFourthStep": "Добавление на портал",
"ImportWizardSecondStep": "Установка соответствия",
"ImportWizardThirdStep": "Проверка",
"InviteLink": "Пригласительная ссылка",
"LastName": "Фамилия",
"LblActive": "Активный",
"LblByName": "Фамилия",
"LblByType": "Тип",
"LblCancelButton": "Отмена",
"LblChangeEmail": "Изменить email",
"LblChangePassword": "Сменить пароль",
"LblCreateNew": "Создать",
"LblDeleteProfile": "Удалить профиль",
"LblEdit": "Редактировать",
"LblImportAccounts": "Импортировать аккаунты",
"LblMobilePhone": "Основной телефон",
"LblOKButton": "OK",
"LblOther": "Другое",
"LblPassword": "Пароль",
"LblPending": "Ожидание",
"LblReassignData": "Передать данные",
"LblRemoveData": "Удалить личные данные",
"LblResendInvites": "Отправить приглашения еще раз",
"LblSendActivation": "Отправить ссылку активации еще раз",
"LblSendEmail": "Отправить письмо",
"LblSendMessage": "Отправить сообщение",
"LblStatus": "Статус",
"LblSubscriptions": "Подписки",
"LblTerminated": "Заблокирован",
"LblTips": "Подсказки",
"MainEmail": "Основной Email",
"Members": "Участники",
"NoSameValuesOptions": "Поля на портале не могут иметь одинаковые значения!",
"NotFoundDescription": "В данном разделе нет людей, соответствующих фильтру. Пожалуйста, выберите другие параметры или очистите фильтр, чтобы просмотреть всех людей в этом разделе.",
"NotFoundTitle": "Результатов, соответствующих заданным критериям, не найдено",
"NotImport": "Не импортировать",
"OnTop": "Наверх",
"ProductAdminOpportunities": "Делать то же самое, что и пользователь|Создавать профили и группы|Импортировать профили|Приглашать пользователей",
"ProductDescription": "Добавляйте новых пользователей, приглашайте или импортируйте их. Управляйте пользователями и просматривайте подробную информацию о них.",
"ProductName": "Люди",
"ProductUserOpportunities": "Просматривать профили и группы",
"ReadAboutNonProfit": "Или {0}прочитайте о некоммерческом использовании{1}.",
"ReassignAbortButton": "Прервать передачу",
"ReassignAbortToastrMsg": "Передача данных прервана",
"ReassignButton": "Передать",
"ReassignCrmModule": "CRM",
"ReassignDocumentsModule": "Документы",
"ReassignErrorToastrMsg": "Передача данных прервана из-за ошибки сервера",
"ReassignMailModule": "Почта",
"ReassignmentData": "Передача данных",
"ReassignProjectsModule": "Проекты",
"ReassignRestartButton": "Запустить передачу заново",
"ReassignsProgressNotifyInfo": "Вы можете закрыть эту страницу. Когда процесс завершится, запустившему его администратору придет уведомление на почту.",
"ReassignsProgressText": "Процесс передачи данных запущен, он может занять значительное время.{0}Вы можете закрыть эту страницу. Когда процесс завершится, запустившему его администратору придет уведомление на почту.",
"ReassignsProgressUserInfo": "Процесс передачи данных от пользователя {0} пользователю {1} запущен, он может занять значительное время.",
"ReassignsReadMore": "Подробнее о передаче данных",
"ReassignStatusAborted": "Прервано, часть данных могла быть передана",
"ReassignStatusError": "Ошибка сервера",
"ReassignStatusFinished": "Переданы все данные",
"ReassignStatusNotStarted": "Данные не передавались",
"ReassignStatusQueued": "В очереди",
"ReassignStatusStarted": "Запущено",
"ReassignsToUser": "Сотрудник, которому будут переданы данные, -",
"ReassignsTransferedListHdr": "Будут переданы:",
"ReassignsTransferedListItem1": "Общие и личные документы, которые доступны другим пользователям портала;",
"ReassignsTransferedListItem2": "Открытые проекты, вехи и задачи;",
"ReassignsTransferedListItem3": "Контакты, открытые задачи, незакрытые сделки и мероприятия CRM;",
"ReassignTalkModule": "Чат",
"RemovingAbortButton": "Прервать удаление",
"RemovingAbortToastrMsg": "Удаление данных прервано",
"RemovingData": "Удаление личных данных",
"RemovingErrorToastrMsg": "Удаление данных прервано из-за ошибки сервера",
"RemovingListHdr": "Будут удалены:",
"RemovingListItem1": "Все личные документы;",
"RemovingListItem2": "Файлы отчетов CRM;",
"RemovingListItem3": "Все письма и вложения;",
"RemovingListItem4": "Прикрепленные файлы из Чата;",
"RemovingProgressUserInfo": "Процесс удаления персональных данных пользователя {0} запущен, он может занять значительное время.",
"RemovingReadMore": "Подробнее об удалении личных данных",
"RemovingRestartButton": "Запустить удаление заново",
"RemovingStatusAborted": "Прервано, часть данных могла быть удалена",
"RemovingStatusFinished": "Удалены все данные",
"RemovingStatusNotStarted": "Данные не удалялись",
"ResendInviteDialogAfterActivation": "После того, как пользователи подтвердят приглашение на портал, их статус изменится на 'Активный'",
"ResendInviteDialogHeader": "Отправить приглашение еще раз",
"ResendInviteDialogTargetUsers": "Приглашение на портал будет отправлено еще раз выбранным пользователям со статусом 'Ожидание', которые не заблокированы.",
"SaveButton": "Сохранить",
"SelectAll": "Выбрать всех",
"SelectedCount": "выбрано {0}",
"Settings": "Настройки",
"Show": "Показать",
"ShowOnPage": "Показывать на странице",
"ShowSelectedUserList": "Показать список выбранных пользователей",
"SocialProfiles": "Социальные профили",
"SuccessfullyDeleteUserInfoMessage": "Пользователь успешно удален",
"SuccessfullySentNotificationDeleteUserInfoMessage": "Инструкции по удалению Вашего профиля были высланы на адрес электронной почты",
"TariffActiveUserLimit": "Текущий тарифный план позволяет добавить {0}{1} активных пользователей{2}.",
"TerminateButton": "Завершить",
"Title": "Название",
"TitleThumbnailPhoto": "Изменить миниатюры",
"TotalCount": "Общее количество",
"WaitingForConfirmation": "Ожидание подтверждения",
"WriteButton": "Написать письмо"
}

View File

@ -1,3 +1,4 @@
using System.Globalization;
using System.Threading;
using ASC.Api.Core;
@ -113,24 +114,9 @@ namespace ASC.People
app.UseAuthentication();
app.Use(async (context, next) => {
if (SecurityContext.IsAuthenticated)
{
var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
var culture = user.GetCulture();
Thread.CurrentThread.CurrentCulture = user.GetCulture();
Thread.CurrentThread.CurrentCulture = user.GetCulture();
}
//
await next.Invoke();
});
app.UseCultureMiddleware();
app.Use(async (context, next) =>
{
context.Response.RegisterForDispose(new DisposableHttpContext(context));
await next();
});
app.UseDisposeMiddleware();
app.UseEndpoints(endpoints =>
{

View File

@ -13,10 +13,15 @@
<Copyright>(c) Ascensio System SIA. All rights reserved</Copyright>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Controllers\LdapController.cs" />
<Compile Remove="Controllers\SsoSettingsV2Controller.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview7.19365.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview7.19362.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0-preview6-19319-03" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0-preview7-19378-04" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,433 @@
/*
*
* (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.Diagnostics;
using System.Linq;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;
using Newtonsoft.Json;
using ASC.Notify.Cron;
using ASC.Web.Api.Routing;
using ASC.Web.Core.PublicResources;
namespace ASC.Api.Settings
{
public partial class SettingsApi
{
/// <summary>
/// Returns current portal LDAP settings
/// </summary>
/// <short>
/// Get LDAP settings
/// </short>
/// <returns>LDAPSupportSettings object</returns>
[Read("ldap")]
public LdapSettings GetLdapSettings()
{
CheckLdapPermissions();
var settings = LdapSettings.Load();
settings = settings.Clone() as LdapSettings; // clone LdapSettings object for clear password (potencial AscCache.Memory issue)
if (settings == null)
return new LdapSettings().GetDefault() as LdapSettings;
settings.Password = null;
settings.PasswordBytes = null;
if (settings.IsDefault)
return settings;
var defaultSettings = settings.GetDefault();
if (settings.Equals(defaultSettings))
settings.IsDefault = true;
return settings;
}
/// <summary>
/// Returns current portal LDAP AutoSync cron expression if any
/// </summary>
/// <short>
/// Get LDAP AutoSync Cron expression
/// </short>
/// <returns>string or null</returns>
[Read("ldap/cron")]
public string GetLdapCronSettings()
{
CheckLdapPermissions();
var settings = LdapCronSettings.Load();
if (settings == null)
settings = new LdapCronSettings().GetDefault() as LdapCronSettings;
if (string.IsNullOrEmpty(settings.Cron))
return null;
return settings.Cron;
}
/// <summary>
/// Sets current portal LDAP AutoSync cron expression
/// </summary>
/// <short>
/// Sets LDAP AutoSync Cron expression
/// </short>
[Create("ldap/cron")]
public void SetLdapCronSettings(string cron)
{
CheckLdapPermissions();
if (!string.IsNullOrEmpty(cron))
{
new CronExpression(cron); // validate
if (!LdapSettings.Load().EnableLdapAuthentication)
{
throw new Exception(Resource.LdapSettingsErrorCantSaveLdapSettings);
}
}
var settings = LdapCronSettings.Load();
if (settings == null)
settings = new LdapCronSettings();
settings.Cron = cron;
settings.Save();
var t = CoreContext.TenantManager.GetCurrentTenant();
if (!string.IsNullOrEmpty(cron))
{
LdapNotifyHelper.UnregisterAutoSync(t);
LdapNotifyHelper.RegisterAutoSync(t, cron);
}
else
{
LdapNotifyHelper.UnregisterAutoSync(t);
}
}
/// <summary>
/// Start sync users and groups process by LDAP
/// </summary>
/// <short>
/// Sync LDAP
/// </short>
[Read("ldap/sync")]
public LdapOperationStatus SyncLdap()
{
CheckLdapPermissions();
var operations = LDAPTasks.GetTasks()
.Where(t => t.GetProperty<int>(LdapOperation.OWNER) == TenantProvider.CurrentTenantID)
.ToList();
var hasStarted = operations.Any(o =>
{
var opType = o.GetProperty<LdapOperationType>(LdapOperation.OPERATION_TYPE);
return o.Status <= DistributedTaskStatus.Running &&
(opType == LdapOperationType.Sync || opType == LdapOperationType.Save);
});
if (hasStarted)
{
return GetLdapOperationStatus();
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapSettings = LdapSettings.Load();
var ldapLocalization = new LdapLocalization(Resource.ResourceManager);
var tenant = CoreContext.TenantManager.GetCurrentTenant();
var op = new LdapSaveSyncOperation(ldapSettings, tenant, LdapOperationType.Sync, ldapLocalization);
return QueueTask(op);
}
/// <summary>
/// Starts the process of collecting preliminary changes on the portal according to the selected LDAP settings
/// </summary>
/// <short>
/// Sync LDAP
/// </short>
[Read("ldap/sync/test")]
public LdapOperationStatus TestLdapSync()
{
CheckLdapPermissions();
var operations = LDAPTasks.GetTasks()
.Where(t => t.GetProperty<int>(LdapOperation.OWNER) == TenantProvider.CurrentTenantID)
.ToList();
var hasStarted = operations.Any(o =>
{
var opType = o.GetProperty<LdapOperationType>(LdapOperation.OPERATION_TYPE);
return o.Status <= DistributedTaskStatus.Running &&
(opType == LdapOperationType.SyncTest || opType == LdapOperationType.SaveTest);
});
if (hasStarted)
{
return GetLdapOperationStatus();
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapSettings = LdapSettings.Load();
var ldapLocalization = new LdapLocalization(Resource.ResourceManager);
var tenant = CoreContext.TenantManager.GetCurrentTenant();
var op = new LdapSaveSyncOperation(ldapSettings, tenant, LdapOperationType.SyncTest, ldapLocalization);
return QueueTask(op);
}
/// <summary>
/// Save LDAP settings and start import/sync users and groups process by LDAP
/// </summary>
/// <short>
/// Save LDAP settings
/// </short>
/// <param name="settings">LDAPSupportSettings serialized string</param>
/// <param name="acceptCertificate">Flag permits errors of checking certificates</param>
[Create("ldap")]
public LdapOperationStatus SaveLdapSettings(string settings, bool acceptCertificate)
{
CheckLdapPermissions();
var operations = LDAPTasks.GetTasks()
.Where(t => t.GetProperty<int>(LdapOperation.OWNER) == TenantProvider.CurrentTenantID).ToList();
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapSettings = JsonConvert.DeserializeObject<LdapSettings>(settings);
ldapSettings.AcceptCertificate = acceptCertificate;
if (!ldapSettings.EnableLdapAuthentication)
{
SetLdapCronSettings(null);
}
//ToDo
ldapSettings.AccessRights.Clear();
var ldapLocalization = new LdapLocalization(Resource.ResourceManager);
var tenant = CoreContext.TenantManager.GetCurrentTenant();
var op = new LdapSaveSyncOperation(ldapSettings, tenant, LdapOperationType.Save, ldapLocalization, CurrentUser.ToString());
return QueueTask(op);
}
/// <summary>
/// Starts the process of collecting preliminary changes on the portal according to the LDAP settings
/// </summary>
/// <short>
/// Save LDAP settings
/// </short>
[Create("ldap/save/test")]
public LdapOperationStatus TestLdapSave(string settings, bool acceptCertificate)
{
CheckLdapPermissions();
var operations = LDAPTasks.GetTasks()
.Where(t => t.GetProperty<int>(LdapOperation.OWNER) == TenantProvider.CurrentTenantID)
.ToList();
var hasStarted = operations.Any(o =>
{
var opType = o.GetProperty<LdapOperationType>(LdapOperation.OPERATION_TYPE);
return o.Status <= DistributedTaskStatus.Running &&
(opType == LdapOperationType.SyncTest || opType == LdapOperationType.SaveTest);
});
if (hasStarted)
{
return GetLdapOperationStatus();
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapSettings = JsonConvert.DeserializeObject<LdapSettings>(settings);
ldapSettings.AcceptCertificate = acceptCertificate;
var ldapLocalization = new LdapLocalization(Resource.ResourceManager);
var tenant = CoreContext.TenantManager.GetCurrentTenant();
var op = new LdapSaveSyncOperation(ldapSettings, tenant, LdapOperationType.SaveTest, ldapLocalization, CurrentUser.ToString());
return QueueTask(op);
}
/// <summary>
/// Returns LDAP sync process status
/// </summary>
/// <short>
/// Get LDAP sync process status
/// </short>
/// <returns>LDAPSupportSettingsResult object</returns>
[Read("ldap/status")]
public LdapOperationStatus GetLdapOperationStatus()
{
CheckLdapPermissions();
return ToLdapOperationStatus();
}
/// <summary>
/// Returns LDAP default settings
/// </summary>
/// <short>
/// Get LDAP default settings
/// </short>
/// <returns>LDAPSupportSettings object</returns>
[Read("ldap/default")]
public LdapSettings GetDefaultLdapSettings()
{
CheckLdapPermissions();
return new LdapSettings().GetDefault() as LdapSettings;
}
private static LdapOperationStatus ToLdapOperationStatus()
{
var operations = LDAPTasks.GetTasks().ToList();
foreach (var o in operations)
{
if (!string.IsNullOrEmpty(o.InstanseId) &&
Process.GetProcesses().Any(p => p.Id == int.Parse(o.InstanseId)))
continue;
o.SetProperty(LdapOperation.PROGRESS, 100);
LDAPTasks.RemoveTask(o.Id);
}
var operation =
operations
.FirstOrDefault(t => t.GetProperty<int>(LdapOperation.OWNER) == TenantProvider.CurrentTenantID);
if (operation == null)
{
return null;
}
if (DistributedTaskStatus.Running < operation.Status)
{
operation.SetProperty(LdapOperation.PROGRESS, 100);
LDAPTasks.RemoveTask(operation.Id);
}
var certificateConfirmRequest = operation.GetProperty<LdapCertificateConfirmRequest>(LdapOperation.CERT_REQUEST);
var result = new LdapOperationStatus
{
Id = operation.Id,
Completed = operation.GetProperty<bool>(LdapOperation.FINISHED),
Percents = operation.GetProperty<int>(LdapOperation.PROGRESS),
Status = operation.GetProperty<string>(LdapOperation.RESULT),
Error = operation.GetProperty<string>(LdapOperation.ERROR),
CertificateConfirmRequest = certificateConfirmRequest,
Source = operation.GetProperty<string>(LdapOperation.SOURCE),
OperationType = Enum.GetName(typeof(LdapOperationType),
(LdapOperationType)Convert.ToInt32(operation.GetProperty<string>(LdapOperation.OPERATION_TYPE))),
Warning = operation.GetProperty<string>(LdapOperation.WARNING)
};
if (!(string.IsNullOrEmpty(result.Warning))) {
operation.SetProperty(LdapOperation.WARNING, ""); // "mark" as read
}
return result;
}
private static void CheckLdapPermissions()
{
SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
if (!SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString()) ||
(CoreContext.Configuration.Standalone &&
!CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Ldap))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Ldap");
}
}
private LdapOperationStatus QueueTask(LdapOperation op)
{
LDAPTasks.QueueTask(op.RunJob, op.GetDistributedTask());
return ToLdapOperationStatus();
}
private LdapOperationStatus GetStartProcessError()
{
var result = new LdapOperationStatus
{
Id = null,
Completed = true,
Percents = 0,
Status = "",
Error = Resource.LdapSettingsTooManyOperations,
CertificateConfirmRequest = null,
Source = ""
};
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,234 @@
/*
*
* (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.Diagnostics;
using System.Linq;
using ASC.Api.Core;
using ASC.Api.Settings.Smtp;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Configuration;
using ASC.Core.Tenants;
using ASC.MessagingSystem;
using ASC.Web.Api.Routing;
using ASC.Web.Core.PublicResources;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Utility;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
namespace ASC.Api.Settings
{
[DefaultRoute]
[ApiController]
public class SmtpSettingsController : ControllerBase
{
private static DistributedTaskQueue SMTPTasks { get; } = new DistributedTaskQueue("smtpOperations");
public Tenant Tenant { get { return ApiContext.Tenant; } }
public ApiContext ApiContext { get; }
public LogManager LogManager { get; }
public MessageService MessageService { get; }
public StudioNotifyService StudioNotifyService { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
public SmtpSettingsController(LogManager logManager,
MessageService messageService,
StudioNotifyService studioNotifyService,
ApiContext apiContext)
{
LogManager = logManager;
MessageService = messageService;
StudioNotifyService = studioNotifyService;
ApiContext = apiContext;
}
[Read("smtp")]
public SmtpSettingsWrapper GetSmtpSettings()
{
CheckSmtpPermissions();
var settings = ToSmtpSettings(CoreContext.Configuration.SmtpSettings, true);
return settings;
}
[Create("smtp")]
public SmtpSettingsWrapper SaveSmtpSettings(SmtpSettingsWrapper smtpSettings)
{
CheckSmtpPermissions();
//TODO: Add validation check
if(smtpSettings == null)
throw new ArgumentNullException("smtpSettings");
SecurityContext.DemandPermissions(Tenant, SecutiryConstants.EditPortalSettings);
var settingConfig = ToSmtpSettingsConfig(smtpSettings);
CoreContext.Configuration.SmtpSettings = settingConfig;
var settings = ToSmtpSettings(settingConfig, true);
return settings;
}
[Delete("smtp")]
public SmtpSettingsWrapper ResetSmtpSettings()
{
CheckSmtpPermissions();
if (!CoreContext.Configuration.SmtpSettings.IsDefaultSettings)
{
SecurityContext.DemandPermissions(Tenant, SecutiryConstants.EditPortalSettings);
CoreContext.Configuration.SmtpSettings = null;
}
var current = CoreContext.Configuration.Standalone ? CoreContext.Configuration.SmtpSettings : SmtpSettings.Empty;
return ToSmtpSettings(current, true);
}
[Read("smtp/test")]
public SmtpOperationStatus TestSmtpSettings()
{
CheckSmtpPermissions();
var settings = ToSmtpSettings(CoreContext.Configuration.SmtpSettings);
var smtpTestOp = new SmtpOperation(settings, Tenant.TenantId, SecurityContext.CurrentAccount.ID);
SMTPTasks.QueueTask(smtpTestOp.RunJob, smtpTestOp.GetDistributedTask());
return ToSmtpOperationStatus();
}
[Read("smtp/test/status")]
public SmtpOperationStatus GetSmtpOperationStatus()
{
CheckSmtpPermissions();
return ToSmtpOperationStatus();
}
private static SmtpOperationStatus ToSmtpOperationStatus()
{
var operations = SMTPTasks.GetTasks().ToList();
foreach (var o in operations)
{
if (!string.IsNullOrEmpty(o.InstanseId) &&
Process.GetProcesses().Any(p => p.Id == int.Parse(o.InstanseId)))
continue;
o.SetProperty(SmtpOperation.PROGRESS, 100);
SMTPTasks.RemoveTask(o.Id);
}
var operation =
operations
.FirstOrDefault(t => t.GetProperty<int>(SmtpOperation.OWNER) == TenantProvider.CurrentTenantID);
if (operation == null)
{
return null;
}
if (DistributedTaskStatus.Running < operation.Status)
{
operation.SetProperty(SmtpOperation.PROGRESS, 100);
SMTPTasks.RemoveTask(operation.Id);
}
var result = new SmtpOperationStatus
{
Id = operation.Id,
Completed = operation.GetProperty<bool>(SmtpOperation.FINISHED),
Percents = operation.GetProperty<int>(SmtpOperation.PROGRESS),
Status = operation.GetProperty<string>(SmtpOperation.RESULT),
Error = operation.GetProperty<string>(SmtpOperation.ERROR),
Source = operation.GetProperty<string>(SmtpOperation.SOURCE)
};
return result;
}
public static SmtpSettings ToSmtpSettingsConfig(SmtpSettingsWrapper settingsWrapper)
{
var settingsConfig = new SmtpSettings(
settingsWrapper.Host,
settingsWrapper.Port ?? SmtpSettings.DefaultSmtpPort,
settingsWrapper.SenderAddress,
settingsWrapper.SenderDisplayName)
{
EnableSSL = settingsWrapper.EnableSSL,
EnableAuth = settingsWrapper.EnableAuth
};
if (settingsWrapper.EnableAuth)
{
settingsConfig.SetCredentials(settingsWrapper.CredentialsUserName, settingsWrapper.CredentialsUserPassword);
}
return settingsConfig;
}
private static SmtpSettingsWrapper ToSmtpSettings(SmtpSettings settingsConfig, bool hidePassword = false)
{
return new SmtpSettingsWrapper
{
Host = settingsConfig.Host,
Port = settingsConfig.Port,
SenderAddress = settingsConfig.SenderAddress,
SenderDisplayName = settingsConfig.SenderDisplayName,
CredentialsUserName = settingsConfig.CredentialsUserName,
CredentialsUserPassword = hidePassword ? "" : settingsConfig.CredentialsUserPassword,
EnableSSL = settingsConfig.EnableSSL,
EnableAuth = settingsConfig.EnableAuth
};
}
private static void CheckSmtpPermissions()
{
if (!SetupInfo.IsVisibleSettings(ManagementType.SmtpSettings.ToString()))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Smtp");
}
}
}
}

View File

@ -0,0 +1,219 @@
/*
*
* (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.Linq;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Web.Api.Routing;
using ASC.Web.Core.PublicResources;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;
using Newtonsoft.Json;
namespace ASC.Api.Settings
{
public partial class SettingsApi
{
/// <summary>
/// Returns current portal SSO settings
/// </summary>
/// <short>
/// Get SSO settings
/// </short>
/// <returns>SsoSettingsV2 object</returns>
[Read("ssov2")]
public SsoSettingsV2 GetSsoSettingsV2()
{
CheckSsoPermissions();
var settings = SsoSettingsV2.Load();
if(string.IsNullOrEmpty(settings.SpLoginLabel))
settings.SpLoginLabel = SsoSettingsV2.SSO_SP_LOGIN_LABEL;
return settings;
}
/// <summary>
/// Returns default portal SSO settings
/// </summary>
/// <short>
/// Get default SSO settings
/// </short>
/// <returns>SsoSettingsV2 object</returns>
[Read("ssov2/default")]
public SsoSettingsV2 GetDefaultSsoSettingsV2()
{
CheckSsoPermissions();
return new SsoSettingsV2().GetDefault() as SsoSettingsV2;
}
/// <summary>
/// Returns SSO settings constants
/// </summary>
/// <short>
/// Get SSO settings constants
/// </short>
/// <returns>object</returns>
[Read("ssov2/constants")]
public object GetSsoSettingsV2Constants()
{
return new
{
SsoNameIdFormatType = new SsoNameIdFormatType(),
SsoBindingType = new SsoBindingType(),
SsoSigningAlgorithmType = new SsoSigningAlgorithmType(),
SsoEncryptAlgorithmType = new SsoEncryptAlgorithmType(),
SsoSpCertificateActionType = new SsoSpCertificateActionType(),
SsoIdpCertificateActionType = new SsoIdpCertificateActionType()
};
}
/// <summary>
/// Save SSO settings for current portal
/// </summary>
/// <short>
/// Save SSO settings
/// </short>
/// <param name="serializeSettings">serialized SsoSettingsV2 object</param>
/// <returns>SsoSettingsV2 object</returns>
[Create("ssov2")]
public SsoSettingsV2 SaveSsoSettingsV2(string serializeSettings)
{
CheckSsoPermissions();
if (string.IsNullOrEmpty(serializeSettings))
throw new ArgumentException(Resource.SsoSettingsCouldNotBeNull);
var settings = JsonConvert.DeserializeObject<SsoSettingsV2>(serializeSettings);
if (settings == null)
throw new ArgumentException(Resource.SsoSettingsCouldNotBeNull);
if (string.IsNullOrWhiteSpace(settings.IdpSettings.EntityId))
throw new Exception(Resource.SsoSettingsInvalidEntityId);
if (string.IsNullOrWhiteSpace(settings.IdpSettings.SsoUrl) ||
!CheckUri(settings.IdpSettings.SsoUrl))
throw new Exception(string.Format(Resource.SsoSettingsInvalidBinding, "SSO " + settings.IdpSettings.SsoBinding));
if (!string.IsNullOrWhiteSpace(settings.IdpSettings.SloUrl) &&
!CheckUri(settings.IdpSettings.SloUrl))
throw new Exception(string.Format(Resource.SsoSettingsInvalidBinding, "SLO " + settings.IdpSettings.SloBinding));
if (string.IsNullOrWhiteSpace(settings.FieldMapping.FirstName) ||
string.IsNullOrWhiteSpace(settings.FieldMapping.LastName) ||
string.IsNullOrWhiteSpace(settings.FieldMapping.Email))
throw new Exception(Resource.SsoSettingsInvalidMapping);
if (string.IsNullOrEmpty(settings.SpLoginLabel))
{
settings.SpLoginLabel = SsoSettingsV2.SSO_SP_LOGIN_LABEL;
}
else if (settings.SpLoginLabel.Length > 100)
{
settings.SpLoginLabel = settings.SpLoginLabel.Substring(0, 100);
}
if (!settings.Save())
throw new Exception(Resource.SsoSettingsCantSaveSettings);
if(!settings.EnableSso)
ConverSsoUsersToOrdinary();
var messageAction = settings.EnableSso ? MessageAction.SSOEnabled : MessageAction.SSODisabled;
MessageService.Send(HttpContext.Current.Request, messageAction);
return settings;
}
/// <summary>
/// Reset SSO settings for current portal
/// </summary>
/// <short>
/// Reset SSO settings
/// </short>
/// <returns>SsoSettingsV2 object</returns>
[Delete("ssov2")]
public SsoSettingsV2 ResetSsoSettingsV2()
{
CheckSsoPermissions();
var defaultSettings = new SsoSettingsV2().GetDefault() as SsoSettingsV2;
if (defaultSettings != null && !defaultSettings.Save())
throw new Exception(Resource.SsoSettingsCantSaveSettings);
ConverSsoUsersToOrdinary();
MessageService.Send(HttpContext.Current.Request, MessageAction.SSODisabled);
return defaultSettings;
}
private static void ConverSsoUsersToOrdinary()
{
var ssoUsers = CoreContext.UserManager.GetUsers().Where(u => u.IsSSO()).ToList();
if(!ssoUsers.Any())
return;
foreach (var existingSsoUser in ssoUsers)
{
existingSsoUser.SsoNameId = null;
existingSsoUser.SsoSessionId = null;
existingSsoUser.ConvertExternalContactsToOrdinary();
CoreContext.UserManager.SaveUserInfo(existingSsoUser);
}
}
private static bool CheckUri(string uriName)
{
Uri uriResult;
return Uri.TryCreate(uriName, UriKind.Absolute, out uriResult) &&
(uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
}
private static void CheckSsoPermissions()
{
SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
if (!SetupInfo.IsVisibleSettings(ManagementType.SingleSignOnSettings.ToString()) ||
(CoreContext.Configuration.Standalone &&
!CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Sso))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Sso");
}
}
}
}

View File

@ -0,0 +1,97 @@
/*
*
* (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.Runtime.Serialization;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Web.Core.Files;
namespace ASC.Api.Settings
{
[DataContract(Name = "buildversion", Namespace = "")]
public class BuildVersion
{
[DataMember]
public string CommunityServer { get; set; }
[DataMember(EmitDefaultValue = false)]
public string DocumentServer { get; set; }
[DataMember(EmitDefaultValue = false)]
public string MailServer { get; set; }
public static BuildVersion GetCurrentBuildVersion()
{
return new BuildVersion
{
CommunityServer = GetCommunityVersion(),
DocumentServer = GetDocumentVersion(),
MailServer = GetMailServerVersion()
};
}
private static string GetCommunityVersion()
{
return ConfigurationManager.AppSettings["version:number"] ?? "8.5.0";
}
private static string GetDocumentVersion()
{
return "";
//TODO
/*
if (string.IsNullOrEmpty(FilesLinkUtility.DocServiceApiUrl))
return null;
return DocumentServiceConnector.GetVersion();*/
}
private static string GetMailServerVersion()
{
//TODO
return "";
/*
try
{
var engineFactory = new EngineFactory(
CoreContext.TenantManager.GetCurrentTenant().TenantId,
SecurityContext.CurrentAccount.ID.ToString());
var version = engineFactory.ServerEngine.GetServerVersion();
return version;
}
catch (Exception e)
{
LogManager.GetLogger("ASC").Warn(e.Message, e);
}
return null;*/
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ASC.Web.Api.Models
{
public class IpRestrictionsModel
{
public IEnumerable<string> Ips { get; set; }
public bool Enable { get; set; }
}
}

View File

@ -0,0 +1,145 @@
/*
*
* (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.Generic;
using System.Linq;
using System.Runtime.Serialization;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Web.Core;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;
namespace ASC.Web.Studio.Core.Quota
{
[DataContract(Name = "quota", Namespace = "")]
public class QuotaWrapper
{
[DataMember(Name = "storageSize")]
public ulong StorageSize { get; set; }
[DataMember(Name = "maxFileSize")]
public ulong MaxFileSize { get; set; }
[DataMember(Name = "usedSize")]
public ulong UsedSize { get; set; }
[DataMember(Name = "maxUsersCount")]
public int MaxUsersCount { get; set; }
[DataMember(Name = "usersCount")]
public int UsersCount { get; set; }
[DataMember(Name = "availableSize")]
public ulong AvailableSize
{
get { return Math.Max(0, StorageSize > UsedSize ? StorageSize - UsedSize : 0); }
set { throw new NotImplementedException(); }
}
[DataMember(Name = "availableUsersCount")]
public int AvailableUsersCount
{
get { return Math.Max(0, MaxUsersCount - UsersCount); }
set { throw new NotImplementedException(); }
}
[DataMember(Name = "storageUsage")]
public IList<QuotaUsage> StorageUsage { get; set; }
[DataMember(Name = "userStorageSize")]
public long UserStorageSize { get; set; }
[DataMember(Name = "userUsedSize")]
public long UserUsedSize { get; set; }
[DataMember(Name = "userAvailableSize")]
public long UserAvailableSize
{
get { return Math.Max(0, UserStorageSize - UserUsedSize); }
set { throw new NotImplementedException(); }
}
public static QuotaWrapper GetCurrent(Tenant tenant)
{
var quota = TenantExtra.GetTenantQuota();
var quotaRows = TenantStatisticsProvider.GetQuotaRows(tenant.TenantId).ToList();
var result = new QuotaWrapper
{
StorageSize = (ulong)Math.Max(0, quota.MaxTotalSize),
UsedSize = (ulong)Math.Max(0, quotaRows.Sum(r => r.Counter)),
MaxUsersCount = TenantExtra.GetTenantQuota().ActiveUsers,
UsersCount = CoreContext.Configuration.Personal ? 1 : TenantStatisticsProvider.GetUsersCount(tenant),
StorageUsage = quotaRows
.Select(x => new QuotaUsage { Path = x.Path.TrimStart('/').TrimEnd('/'), Size = x.Counter, })
.ToList()
};
if (CoreContext.Configuration.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
{
result.UserStorageSize = CoreContext.Configuration.PersonalMaxSpace;
var webItem = WebItemManager.Instance[WebItemManager.DocumentsProductID];
var spaceUsageManager = webItem.Context.SpaceUsageStatManager as IUserSpaceUsage;
if (spaceUsageManager != null)
result.UserUsedSize = spaceUsageManager.GetUserSpaceUsage(SecurityContext.CurrentAccount.ID);
}
result.MaxFileSize = Math.Min(result.AvailableSize, (ulong)quota.MaxFileSize);
return result;
}
public static QuotaWrapper GetSample()
{
return new QuotaWrapper
{
MaxFileSize = 25 * 1024 * 1024,
StorageSize = 1024 * 1024 * 1024,
UsedSize = 250 * 1024 * 1024,
StorageUsage = new List<QuotaUsage>
{
new QuotaUsage { Size = 100*1024*1024, Path = "crm" },
new QuotaUsage { Size = 150*1024*1024, Path = "files" }
}
};
}
[DataContract(Name = "quota_usage", Namespace = "")]
public class QuotaUsage
{
[DataMember(Name = "path")]
public string Path { get; set; }
[DataMember(Name = "size")]
public long Size { get; set; }
}
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace ASC.Web.Api.Models
{
public class SecurityModel
{
public Guid ProductId { get; set; }
public Guid UserId { get; set; }
public bool Administrator { get; set; }
}
}

View File

@ -0,0 +1,70 @@
/*
*
* (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.Generic;
using System.Runtime.Serialization;
using ASC.Web.Api.Models;
namespace ASC.Api.Settings
{
[DataContract(Name = "security", Namespace = "")]
public class SecurityWrapper
{
[DataMember]
public string WebItemId { get; set; }
[DataMember]
public IEnumerable<EmployeeWraper> Users { get; set; }
[DataMember]
public IEnumerable<GroupWrapperSummary> Groups { get; set; }
[DataMember]
public bool Enabled { get; set; }
[DataMember]
public bool IsSubItem { get; set; }
public static SecurityWrapper GetSample()
{
return new SecurityWrapper
{
WebItemId = Guid.Empty.ToString(),
Enabled = true,
IsSubItem = false,
Groups = new List<GroupWrapperSummary>
{
GroupWrapperSummary.GetSample()
},
Users = new List<EmployeeWraper>
{
EmployeeWraper.GetSample()
}
};
}
}
}

View File

@ -0,0 +1,19 @@
using System;
namespace ASC.Web.Api.Models
{
public class SettingsModel
{
public Guid DefaultProductID { get; set; }
public string Lng { get; set; }
public string TimeZoneID { get; set; }
public string Theme { get; set; }
public bool Show { get; set; } //tips
public int VersionId { get; set; }
}
}

View File

@ -0,0 +1,68 @@
/*
*
* (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.Generic;
using System.Runtime.Serialization;
using ASC.Core.Tenants;
namespace ASC.Api.Settings
{
[DataContract(Name = "settings", Namespace = "")]
public class SettingsWrapper
{
[DataMember]
public string Timezone { get; set; }
[DataMember]
public List<string> TrustedDomains { get; set; }
[DataMember]
public TenantTrustedDomainsType TrustedDomainsType { get; set; }
[DataMember]
public string Culture { get; set; }
[DataMember]
public TimeSpan UtcOffset { get; set; }
[DataMember]
public double UtcHoursOffset { get; set; }
public static SettingsWrapper GetSample()
{
return new SettingsWrapper
{
Culture = "en-US",
Timezone = TimeZoneInfo.Utc.ToString(),
TrustedDomains = new List<string> {"mydomain.com"},
UtcHoursOffset = -8.5,
UtcOffset = TimeSpan.FromHours(-8.5)
};
}
}
}

View File

@ -0,0 +1,264 @@
/*
*
* (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.Net.Sockets;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using ASC.Common.Logging;
using ASC.Common.Security.Authorizing;
using ASC.Common.Threading;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Web.Core.PublicResources;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.Api.Settings.Smtp
{
public class SmtpOperation
{
public const string OWNER = "SMTPOwner";
public const string SOURCE = "SMTPSource";
public const string PROGRESS = "SMTPProgress";
public const string RESULT = "SMTPResult";
public const string ERROR = "SMTPError";
public const string FINISHED = "SMTPFinished";
protected DistributedTask TaskInfo { get; set; }
protected CancellationToken CancellationToken { get; private set; }
protected int Progress { get; private set; }
protected string Source { get; private set; }
protected string Status { get; set; }
protected string Error { get; set; }
protected int CurrentTenant { get; private set; }
protected Guid CurrentUser { get; private set; }
protected ILog Logger { get; private set; }
public SmtpSettingsWrapper SmtpSettings { get; private set; }
private readonly string messageSubject;
private readonly string messageBody;
public SmtpOperation(SmtpSettingsWrapper smtpSettings, int tenant, Guid user)
{
SmtpSettings = smtpSettings;
CurrentTenant = tenant;
CurrentUser = user;
//todo
//messageSubject = WebstudioNotifyPatternResource.subject_smtp_test;
//messageBody = WebstudioNotifyPatternResource.pattern_smtp_test;
Source = "";
Progress = 0;
Status = "";
Error = "";
Source = "";
TaskInfo = new DistributedTask();
Logger = LogManager.GetLogger("ASC");
}
public void RunJob(DistributedTask _, CancellationToken cancellationToken)
{
try
{
CancellationToken = cancellationToken;
SetProgress(5, "Setup tenant");
CoreContext.TenantManager.SetCurrentTenant(CurrentTenant);
SetProgress(10, "Setup user");
SecurityContext.AuthenticateMe(CurrentTenant, CurrentUser); //Core.Configuration.Constants.CoreSystem);
SetProgress(15, "Find user data");
var currentUser = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
SetProgress(20, "Create mime message");
var toAddress = new MailboxAddress(currentUser.UserName, currentUser.Email);
var fromAddress = new MailboxAddress(SmtpSettings.SenderDisplayName, SmtpSettings.SenderAddress);
var mimeMessage = new MimeMessage
{
Subject = messageSubject
};
mimeMessage.From.Add(fromAddress);
mimeMessage.To.Add(toAddress);
var bodyBuilder = new BodyBuilder
{
TextBody = messageBody
};
mimeMessage.Body = bodyBuilder.ToMessageBody();
mimeMessage.Headers.Add("Auto-Submitted", "auto-generated");
using (var client = GetSmtpClient())
{
SetProgress(40, "Connect to host");
client.Connect(SmtpSettings.Host, SmtpSettings.Port.GetValueOrDefault(25),
SmtpSettings.EnableSSL ? SecureSocketOptions.Auto : SecureSocketOptions.None, cancellationToken);
if (SmtpSettings.EnableAuth)
{
SetProgress(60, "Authenticate");
client.Authenticate(SmtpSettings.CredentialsUserName,
SmtpSettings.CredentialsUserPassword, cancellationToken);
}
SetProgress(80, "Send test message");
client.Send(FormatOptions.Default, mimeMessage, cancellationToken);
}
}
catch (AuthorizingException authError)
{
Error = Resource.ErrorAccessDenied; // "No permissions to perform this action";
Logger.Error(Error, new SecurityException(Error, authError));
}
catch (AggregateException ae)
{
ae.Flatten().Handle(e => e is TaskCanceledException || e is OperationCanceledException);
}
catch (SocketException ex)
{
Error = ex.Message; //TODO: Add translates of ordinary cases
Logger.Error(ex.ToString());
}
catch (AuthenticationException ex)
{
Error = ex.Message; //TODO: Add translates of ordinary cases
Logger.Error(ex.ToString());
}
catch (Exception ex)
{
Error = ex.Message; //TODO: Add translates of ordinary cases
Logger.Error(ex.ToString());
}
finally
{
try
{
TaskInfo.SetProperty(FINISHED, true);
PublishTaskInfo();
SecurityContext.Logout();
}
catch (Exception ex)
{
Logger.ErrorFormat("LdapOperation finalization problem. {0}", ex);
}
}
}
public SmtpClient GetSmtpClient()
{
var sslCertificatePermit = ConfigurationManager.AppSettings["mail.certificate-permit"] != null &&
Convert.ToBoolean(ConfigurationManager.AppSettings["mail.certificate-permit"]);
return new SmtpClient
{
ServerCertificateValidationCallback = (sender, certificate, chain, errors) =>
sslCertificatePermit ||
MailKit.MailService.DefaultServerCertificateValidationCallback(sender, certificate, chain, errors),
Timeout = (int) TimeSpan.FromSeconds(30).TotalMilliseconds
};
}
public virtual DistributedTask GetDistributedTask()
{
FillDistributedTask();
return TaskInfo;
}
protected virtual void FillDistributedTask()
{
TaskInfo.SetProperty(SOURCE, Source);
TaskInfo.SetProperty(OWNER, CurrentTenant);
TaskInfo.SetProperty(PROGRESS, Progress < 100 ? Progress : 100);
TaskInfo.SetProperty(RESULT, Status);
TaskInfo.SetProperty(ERROR, Error);
//TaskInfo.SetProperty(PROCESSED, successProcessed);
}
protected int GetProgress()
{
return Progress;
}
const string PROGRESS_STRING = "Progress: {0}% {1} {2}";
public void SetProgress(int? currentPercent = null, string currentStatus = null, string currentSource = null)
{
if (!currentPercent.HasValue && currentStatus == null && currentSource == null)
return;
if (currentPercent.HasValue)
Progress = currentPercent.Value;
if (currentStatus != null)
Status = currentStatus;
if (currentSource != null)
Source = currentSource;
Logger.InfoFormat(PROGRESS_STRING, Progress, Status, Source);
PublishTaskInfo();
}
protected void PublishTaskInfo()
{
FillDistributedTask();
TaskInfo.PublishChanges();
}
}
}

View File

@ -0,0 +1,65 @@
/*
*
* (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.Runtime.Serialization;
namespace ASC.Api.Settings.Smtp
{
[DataContract]
public class SmtpOperationStatus
{
[DataMember]
public bool Completed { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public string Status { get; set; }
[DataMember]
public string Error { get; set; }
[DataMember]
public int Percents { get; set; }
[DataMember]
public string Source { get; set; }
public static SmtpOperationStatus GetSample()
{
return new SmtpOperationStatus
{
Id = "{some-random-guid}",
Error = "",
Percents = 0,
Completed = true,
Status = "",
Source = ""
};
}
}
}

View File

@ -0,0 +1,73 @@
/*
*
* (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.Runtime.Serialization;
namespace ASC.Api.Settings.Smtp
{
[DataContract(Name = "quota", Namespace = "")]
public class SmtpSettingsWrapper
{
[DataMember]
public string Host { get; set; }
[DataMember]
public int? Port { get; set; }
[DataMember]
public string SenderAddress { get; set; }
[DataMember]
public string SenderDisplayName { get; set; }
[DataMember]
public string CredentialsUserName { get; set; }
[DataMember]
public string CredentialsUserPassword { get; set; }
[DataMember]
public bool EnableSSL { get; set; }
[DataMember]
public bool EnableAuth { get; set; }
public static SmtpSettingsWrapper GetSample()
{
return new SmtpSettingsWrapper
{
Host = "mail.example.com",
Port = 25,
CredentialsUserName = "notify@example.com",
CredentialsUserPassword = "{password}",
EnableAuth = true,
EnableSSL = false,
SenderAddress = "notify@example.com",
SenderDisplayName = "Postman"
};
}
}
}

View File

@ -0,0 +1,89 @@
/*
*
* (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.Runtime.Serialization;
namespace ASC.Api.Settings
{
[DataContract(Name = "statistics", Namespace = "")]
public class UsageSpaceStatItemWrapper
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Icon { get; set; }
[DataMember]
public bool Disabled { get; set; }
[DataMember]
public string Size { get; set; }
[DataMember]
public string Url { get; set; }
public static UsageSpaceStatItemWrapper GetSample()
{
return new UsageSpaceStatItemWrapper
{
Name = "Item name",
Icon = "Item icon path",
Disabled = false,
Size = "0 Byte",
Url = "Item url"
};
}
}
[DataContract(Name = "statistics", Namespace = "")]
public class ChartPointWrapper
{
[DataMember]
public string DisplayDate { get; set; }
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public int Hosts { get; set; }
[DataMember]
public int Hits { get; set; }
public static ChartPointWrapper GetSample()
{
return new ChartPointWrapper
{
DisplayDate = DateTime.Now.ToShortDateString(),
Date = DateTime.Now,
Hosts = 0,
Hits = 0
};
}
}
}

View File

@ -0,0 +1,11 @@
using System.Collections.Generic;
using ASC.Api.Collections;
namespace ASC.Web.Api.Models
{
public class StorageModel
{
public string Module { get; set; }
public IEnumerable<ItemKeyValuePair<string, string>> Props { get; set; }
}
}

View File

@ -0,0 +1,79 @@
/*
*
* (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.Collections.Generic;
using System.Linq;
using ASC.Core.Common.Configuration;
using ASC.Core.Common.Settings;
using ASC.Data.Storage.Configuration;
using ASC.Web.Studio.UserControls.Management;
namespace ASC.Api.Settings
{
public class StorageWrapper
{
public string Id { get; set; }
public string Title { get; set; }
public List<AuthKey> Properties { get; set; }
public bool Current { get; set; }
public bool IsSet { get; set; }
public StorageWrapper(DataStoreConsumer consumer, StorageSettings current)
{
StorageWrapperInit(consumer, current);
}
public StorageWrapper(DataStoreConsumer consumer, CdnStorageSettings current)
{
StorageWrapperInit(consumer, current);
}
private void StorageWrapperInit<T>(DataStoreConsumer consumer, BaseStorageSettings<T> current) where T : class, ISettings, new()
{
Id = consumer.Name;
Title = consumer.GetResourceString(consumer.Name) ?? consumer.Name;
Current = consumer.Name == current.Module;
IsSet = consumer.IsSet;
var props = Current
? current.Props
: current.Switch(consumer).AdditionalKeys.ToDictionary(r => r, a => consumer[a]);
Properties = props.Select(
r => new AuthKey
{
Name = r.Key,
Value = r.Value,
Title = consumer.GetResourceString(consumer.Name + r.Key) ?? r.Key
}).ToList();
}
}
}

View File

@ -0,0 +1,43 @@
/*
*
* (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.Collections.Generic;
using ASC.Core;
namespace ASC.Api.Settings
{
public class TenantVersionWrapper
{
public int Current { get; set; }
public IEnumerable<TenantVersion> Versions { get; set; }
public TenantVersionWrapper(int version, IEnumerable<TenantVersion> tenantVersions)
{
Current = version;
Versions = tenantVersions;
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace ASC.Web.Api.Models
{
public class TfaModel
{
public string Type { get; set; }
public Guid Id { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using ASC.Api.Collections;
namespace ASC.Web.Api.Models
{
public class WebItemSecurityModel
{
public string Id { get; set; }
public bool Enabled { get; set; }
public IEnumerable<Guid> Subjects { get; set; }
public IEnumerable<ItemKeyValuePair<string, bool>> Items { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using ASC.Api.Collections;
using Microsoft.AspNetCore.Http;
namespace ASC.Web.Api.Models
{
public class WhiteLabelModel
{
public IEnumerable<IFormFile> Attachments { get; set; }
public string LogoText { get; set; }
public IEnumerable<ItemKeyValuePair<int, string>> Logo { get; set; }
}
}

View File

@ -12,11 +12,12 @@ using ASC.Data.Reassigns;
using ASC.Data.Storage.Configuration;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Studio.Core.Notify;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
@ -77,6 +78,8 @@ namespace ASC.Web.Api
services.AddLogManager()
.AddStorage()
.AddWebItemManager()
.AddScoped(r => new ApiContext(r.GetService<IHttpContextAccessor>().HttpContext))
.AddSingleton<StudioNotifyService>()
.AddScoped<MessageService>()
.AddScoped<QueueWorkerReassign>()
.AddScoped<QueueWorkerRemove>();
@ -106,23 +109,9 @@ namespace ASC.Web.Api
app.UseAuthentication();
app.Use(async (context, next) => {
if (SecurityContext.IsAuthenticated)
{
var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
var culture = user.GetCulture();
Thread.CurrentThread.CurrentCulture = user.GetCulture();
Thread.CurrentThread.CurrentCulture = user.GetCulture();
}
await next.Invoke();
});
app.UseCultureMiddleware();
app.Use(async (context, next) =>
{
context.Response.RegisterForDispose(new DisposableHttpContext(context));
await next();
});
app.UseDisposeMiddleware();
app.UseEndpoints(endpoints =>
{

View File

@ -1871,10 +1871,12 @@ asap@~2.0.3, asap@~2.0.6:
postcss "^7.0.16"
prop-types "^15.7.2"
rc-tree "^2.1.0"
react-autosize-textarea "^7.0.0"
react-custom-scrollbars "^4.2.1"
react-datepicker "^2.7.0"
react-lifecycles-compat "^3.0.4"
react-toastify "^5.3.2"
react-window "^1.8.5"
reactstrap "^8.0.0"
styled-components "^4.3.2"
@ -1965,6 +1967,11 @@ autoprefixer@^9.4.9:
postcss "^7.0.17"
postcss-value-parser "^4.0.0"
autosize@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.2.tgz#073cfd07c8bf45da4b9fd153437f5bafbba1e4c9"
integrity sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA==
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@ -2860,6 +2867,11 @@ compression@^1.5.2:
safe-buffer "5.1.2"
vary "~1.1.2"
computed-style@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/computed-style/-/computed-style-0.1.4.tgz#7f344fd8584b2e425bedca4a1afc0e300bb05d74"
integrity sha1-fzRP2FhLLkJb7cpKGvwOMAuwXXQ=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -6345,6 +6357,13 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
line-height@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/line-height/-/line-height-0.3.1.tgz#4b1205edde182872a5efa3c8f620b3187a9c54c9"
integrity sha1-SxIF7d4YKHKl76PI9iCzGHqcVMk=
dependencies:
computed-style "~0.1.3"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -6625,7 +6644,7 @@ mem@^4.0.0:
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memoize-one@^5.0.0:
"memoize-one@>=3.1.1 <6", memoize-one@^5.0.0:
version "5.0.5"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
@ -8473,7 +8492,7 @@ prompts@^2.0.1:
kleur "^3.0.2"
sisteransi "^1.0.0"
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -8683,6 +8702,15 @@ react-app-polyfill@^1.0.1:
regenerator-runtime "0.13.2"
whatwg-fetch "3.0.0"
react-autosize-textarea@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/react-autosize-textarea/-/react-autosize-textarea-7.0.0.tgz#4f633e4238de7ba73c1da8fdc307353c50f1c5ab"
integrity sha512-rGQLpGUaELvzy3NKzp0kkcppaUtZTptsyR0PGuLotaJDjwRbT0DpD000yCzETpXseJQ/eMsyVGDDHXjXP93u8w==
dependencies:
autosize "^4.0.2"
line-height "^0.3.1"
prop-types "^15.5.6"
react-custom-scrollbars@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db"
@ -8905,6 +8933,14 @@ react-transition-group@^2.3.1, react-transition-group@^2.6.1:
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
react-window@^1.8.5:
version "1.8.5"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"
integrity sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==
dependencies:
"@babel/runtime" "^7.0.0"
memoize-one ">=3.1.1 <6"
react@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"

View File

@ -32,12 +32,13 @@
"moment": "^2.24.0",
"postcss": "^7.0.16",
"prop-types": "^15.7.2",
"rc-tree": "^2.1.0",
"rc-tree": "^2.1.2",
"react-autosize-textarea": "^7.0.0",
"react-custom-scrollbars": "^4.2.1",
"react-datepicker": "^2.7.0",
"react-lifecycles-compat": "^3.0.4",
"react-toastify": "^5.3.2",
"react-window": "^1.8.5",
"reactstrap": "^8.0.0",
"styled-components": "^4.3.2"
},
@ -50,7 +51,7 @@
"@babel/plugin-transform-destructuring": "7.4.4",
"@babel/plugin-transform-react-constant-elements": "7.2.0",
"@babel/plugin-transform-runtime": "7.4.4",
"@babel/preset-env": "^7.4.4",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "7.0.0",
"@emotion/babel-preset-css-prop": "10.0.9",
"@svgr/rollup": "4.2.0",
@ -91,7 +92,7 @@
"rollup-plugin-babel": "4.3.3",
"rollup-plugin-cleanup": "3.1.1",
"rollup-plugin-commonjs": "10.0.1",
"rollup-plugin-copy": "^3.0.0",
"rollup-plugin-copy": "^3.1.0",
"rollup-plugin-json": "4.0.0",
"rollup-plugin-node-resolve": "5.2.0",
"rollup-plugin-postcss": "^2.0.3",

View File

@ -111,21 +111,6 @@ const EditContainer = styled.div`
background: linear-gradient(180deg, rgba(6, 22, 38, 0) 24.48%, rgba(6, 22, 38, 0.75) 100%);
`;
const EditLink = styled.div`
& > a {
color: ${whiteColor} !important;
span {
color: ${whiteColor};
}
}
&:hover{
color: ${whiteColor} !important;
cursor: pointer;
}
`;
const EmptyIcon = styled(Icons.CameraIcon)`
border-radius: 50%;
`;
@ -140,6 +125,17 @@ const getInitials = userName => {
return initials;
};
const EditLink = styled.div`
padding-left: 10px;
padding-right: 10px;
span {
display: inline-block;
max-width: 100%;
}
`;
const Avatar = React.memo(props => {
//console.log("Avatar render");
const { size, source, userName, role, editing, editLabel, editAction } = props;
@ -155,13 +151,15 @@ const Avatar = React.memo(props => {
</AvatarWrapper>
{editing && (size === 'max') &&
<EditContainer {...props}>
<EditLink onClick={editAction}>
<EditLink>
<Link
type='action'
title={editLabel}
isTextOverflow={true}
fontSize={14}
isHovered={true}
color={whiteColor}
onClick={editAction}
>
{editLabel}
</Link>

View File

@ -1,50 +1,88 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components';
import InputBlock from '../input-block'
import DropDownItem from '../drop-down-item'
import DropDown from '../drop-down'
import { Icons } from '../icons'
import { handleAnyClick } from '../../utils/event';
const StyledComboBox = styled.div`
* {
${props => !props.withBorder && `border-color: transparent !important;`}
}
color: ${props => props.isDisabled ? '#D0D5DA' : '#333333'};
width: ${props =>
(props.scaled && '100%') ||
(props.size === 'base' && '173px') ||
(props.size === 'middle' && '300px') ||
(props.size === 'big' && '350px') ||
(props.size === 'huge' && '500px') ||
(props.size === 'content' && 'fit-content')
};
${state => state.isOpen && `
.input-group-append > div {
-moz-transform: scaleY(-1);
-o-transform: scaleY(-1);
-webkit-transform: scaleY(-1);
transform: scaleY(-1);
}
position: relative;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: #FFFFFF;
border: 1px solid #D0D5DA;
border-radius: 3px;
${props => props.isDisabled && `
border-color: #ECEEF1;
background: #F8F9F9;
`}
& > div > input {
&::placeholder {
font-family: Open Sans;
font-style: normal;
font-weight: 600;
font-size: 13px;
line-height: 20px;
${props => !props.isDisabled && `color: #333333;`}
${props => (!props.withBorder & !props.isDisabled) && `border-bottom: 1px dotted #333333;`}
opacity: 1;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
height: 32px;
:hover{
border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE'};
${props => props.isDisabled && `
border-color: #ECEEF1;
`}
}
`;
const StyledIcon = styled.span`
width: 16px;
const StyledComboButton = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 30px;
margin-left: 8px;
line-height: 14px;
`;
const StyledIcon = styled.div`
width: 16px;
margin-right: 8px;
margin-top: -2px;
`;
const StyledOptionalItem = styled.div`
margin-right: 8px;
`;
const StyledLabel = styled.div`
font-family: Open Sans;
font-style: normal;
font-weight: 600;
font-size: 13px;
white-space: nowrap;
margin-right: 8px;
`;
const StyledArrowIcon = styled.div`
width: 8px;
margin-right: 8px;
margin-left: auto;
${state => state.isOpen && `
transform: scale(1, -1);
margin-top: 8px;
`}
`;
class ComboBox extends React.PureComponent {
@ -79,8 +117,8 @@ class ComboBox extends React.PureComponent {
toggle = (isOpen) => this.setState({ isOpen: isOpen });
comboBoxClick = (e) => {
if (this.props.isDisabled || !!e.target.closest('.input-group-prepend')) return;
if (this.props.isDisabled || e.target.closest('.optionalBlock')) return;
this.setState({
option: this.props.option,
isOpen: !this.state.isOpen
@ -110,7 +148,7 @@ class ComboBox extends React.PureComponent {
getSelectedLabel = () => {
const selectedItem = this.getSelected();
return selectedItem ? selectedItem.label : "1-1";
return selectedItem ? selectedItem.label : this.props.emptyOptionsPlaceholder;
}
componentDidUpdate(prevProps, prevState) {
@ -124,9 +162,9 @@ class ComboBox extends React.PureComponent {
if (this.props.options.length !== prevProps.options.length) { //TODO: Move options from state
const label = this.getSelectedLabel();
this.setState({
this.setState({
options: this.props.options,
boxLabel: label
boxLabel: label
});
}
@ -137,54 +175,67 @@ class ComboBox extends React.PureComponent {
}
render() {
console.log("ComboBox render");
//console.log("ComboBox render");
const dropDownMaxHeightProp = this.props.dropDownMaxHeight ? { maxHeight: this.props.dropDownMaxHeight } : {}
const { dropDownMaxHeight, isDisabled, directionX, directionY, scaled, children } = this.props;
const { boxLabel, boxIcon, isOpen, options } = this.state;
const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight} : {};
const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {};
const boxIconColor = isDisabled ? '#D0D5DA' : '#333333';
const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE';
return (
<StyledComboBox ref={this.ref}
{...this.props}
{...this.state}
data={this.state.boxLabel}
data={boxLabel}
onClick={this.comboBoxClick}
onSelect={this.stopAction}
>
<InputBlock placeholder={this.state.boxLabel}
iconName='ExpanderDownIcon'
iconSize={8}
isIconFill={true}
iconColor='#A3A9AE'
scale={true}
isDisabled={this.props.isDisabled}
isReadOnly={true}
>
{this.state.boxIcon &&
<StyledComboButton>
<StyledOptionalItem className='optionalBlock'>
{children}
</StyledOptionalItem>
{boxIcon &&
<StyledIcon>
{React.createElement(Icons[this.state.boxIcon],
{React.createElement(Icons[boxIcon],
{
size: "scale",
color: this.props.isDisabled ? '#D0D5DA' : '#333333',
size: 'scale',
color: boxIconColor,
isfill: true
})
}
</StyledIcon>}
{this.props.children}
<DropDown
directionX={this.props.directionX}
directionY={this.props.directionY}
manualWidth='100%'
manualY='102%'
isOpen={this.state.isOpen}
{...dropDownMaxHeightProp}
>
{this.state.options.map((option) =>
<DropDownItem {...option}
disabled={option.label === this.state.boxLabel}
onClick={this.optionClick.bind(this, option)}
/>
)}
</DropDown>
</InputBlock>
</StyledIcon>
}
<StyledLabel>
{boxLabel}
</StyledLabel>
<StyledArrowIcon {...this.state}>
{React.createElement(Icons['ExpanderDownIcon'],
{
size: 'scale',
color: arrowIconColor,
isfill: true
})
}
</StyledArrowIcon>
</StyledComboButton>
<DropDown
directionX={directionX}
directionY={directionY}
manualY='102%'
isOpen={isOpen}
{...dropDownMaxHeightProp}
{...dropDownManualWidthProp}
>
{options.map((option) =>
<DropDownItem {...option}
disabled={option.label === boxLabel}
onClick={this.optionClick.bind(this, option)}
/>
)}
</DropDown>
</StyledComboBox>
);
}
@ -199,13 +250,19 @@ ComboBox.propTypes = {
]),
options: PropTypes.array,
onSelect: PropTypes.func,
dropDownMaxHeight: PropTypes.string
dropDownMaxHeight: PropTypes.number,
emptyOptionsPlaceholder: PropTypes.string,
size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']),
scaled: PropTypes.bool,
}
ComboBox.defaultProps = {
isDisabled: false,
withBorder: true,
dropDownMaxHeight: null
emptyOptionsPlaceholder: 'Select',
size: 'base',
scaled: true
}
export default ComboBox;

View File

@ -1,6 +1,9 @@
import React from 'react'
import React, { memo } from 'react'
import styled, { css } from 'styled-components'
import PropTypes from 'prop-types'
import CustomScrollbarsVirtualList from '../scrollbar/custom-scrollbars-virtual-list'
import DropDownItem from '../drop-down-item'
import { FixedSizeList } from "react-window"
const StyledDropdown = styled.div`
font-family: 'Open Sans',sans-serif,Arial;
@ -9,7 +12,7 @@ const StyledDropdown = styled.div`
font-size: 13px;
${props => props.maxHeight && `
max-height: ${props.maxHeight};
max-height: ${props.maxHeight}px;
overflow-y: auto;
`}
@ -42,30 +45,87 @@ const Arrow = styled.div`
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9.27954 1.12012C10.8122 -0.295972 13.1759 -0.295971 14.7086 1.12012L18.8406 4.93793C19.5796 5.62078 20.5489 6 21.5551 6H24H0H2.43299C3.4392 6 4.40845 5.62077 5.1475 4.93793L9.27954 1.12012Z' fill='%23206FA4'/%3E%3C/svg%3E");
`;
const DropDown = React.memo(props => {
//console.log("DropDown render");
const Row = memo(({ data, index, style }) => {
const option = data[index];
return (
<StyledDropdown {...props}>
{props.withArrow && <Arrow directionX={props.directionX} />}
{props.children}
</StyledDropdown>
<DropDownItem
{...option.props}
style={style} />
);
});
class DropDown extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
width: 100
};
this.dropDown = React.createRef();
};
setDropDownWidthState = () => {
if (this.dropDown.current) {
this.setState({
width: this.dropDown.current.offsetWidth
});
}
}
componentDidMount () {
this.setDropDownWidthState();
};
componentDidUpdate(prevProps) {
if (this.props.opened !== prevProps.opened || this.props.isOpen !== prevProps.isOpen) {
this.setDropDownWidthState();
}
};
render() {
const {maxHeight, withArrow, directionX, children} = this.props;
const dropDownMaxHeightProp = maxHeight ? { height: maxHeight + 'px' } : {};
//console.log("DropDown render");
return (
<StyledDropdown
ref={this.dropDown}
{...this.props}
{...dropDownMaxHeightProp}
>
{withArrow && <Arrow directionX={directionX} />}
{maxHeight
? <FixedSizeList
height={maxHeight}
width={this.state.width}
itemSize={36}
itemCount={children.length}
itemData={children}
outerElementType={CustomScrollbarsVirtualList}
>
{Row}
</FixedSizeList>
: children}
</StyledDropdown>
);
}
};
DropDown.propTypes = {
directionX: PropTypes.oneOf(['left', 'right']),
directionY: PropTypes.oneOf(['bottom', 'top']),
withArrow: PropTypes.bool,
manualWidth: PropTypes.string,
manualY: PropTypes.string,
maxHeight: PropTypes.string
maxHeight: PropTypes.number
};
DropDown.defaultProps = {
directionX: 'left',
directionY: 'bottom',
withArrow: false,
maxHeight: null
withArrow: false
};
export default DropDown

View File

@ -129,16 +129,19 @@ class FilterInput extends React.Component {
this.setState({ sortDirection: !this.state.sortDirection });
}
onChangeFilter(result) {
this.setState({ filterValue: result.filterValue });
this.onFilter(result.filterValue, this.state.sortId, this.state.sortDirection ? "asc" : "desc");
this.setState({
searchText: result.inputValue,
filterValue: result.filterValue,
});
this.onFilter(result.filterValue, this.state.sortId, this.state.sortDirection ? "asc" : "desc", result.inputValue);
}
onSearch(result) {
this.onFilter(result.filterValue, this.state.sortId, this.state.sortDirection ? "asc" : "desc");
}
onFilter(filterValue, sortId, sortDirection) {
onFilter(filterValue, sortId, sortDirection, searchText) {
let result = {
inputValue: this.state.searchText,
inputValue: searchText != undefined ? searchText : this.state.searchText,
filterValue: filterValue,
sortId: sortId,
sortDirection: sortDirection

View File

@ -154,10 +154,11 @@ class GroupButton extends React.PureComponent {
}
render() {
console.log("GroupButton render");
const { label, isDropdown, disabled, isSeparator, isSelect, isIndeterminate, children, checked } = this.props;
//console.log("GroupButton render");
const { label, isDropdown, disabled, isSeparator, isSelect, isIndeterminate, children, checked, dropDownMaxHeight } = this.props;
const color = disabled ? disabledTextColor : textColor;
const itemLabel = !isSelect ? label : this.state.selected;
const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight} : {};
return (
<StyledGroupButton ref={this.ref}>
@ -175,7 +176,7 @@ class GroupButton extends React.PureComponent {
{itemLabel}
<Caret size="small" color={color} />
</StyledDropdownToggle>
<DropDown isOpen={this.state.isOpen}>
<DropDown {...dropDownMaxHeightProp} isOpen={this.state.isOpen}>
{React.Children.map(children, (child) =>
<DropDownItem {...child.props} onClick={this.dropDownItemClick.bind(this, child)} />)}
</DropDown>

View File

@ -5,7 +5,7 @@ import { Icons } from '../icons';
const StyledOuter = styled.div`
width: ${props => props.size ? Math.abs(parseInt(props.size)) + "px" : "20px"};
cursor: ${props => props.isDisabled ? 'default' : 'pointer'};
cursor: ${props => props.isDisabled || !props.isClickable ? 'default' : 'pointer'};
line-height: 0;
`;
class IconButton extends React.Component{
@ -77,7 +77,12 @@ class IconButton extends React.Component{
for (let propsKey in this.props) {
if(typeof this.props[propsKey] != "function" && typeof this.props[propsKey] != "object" && this.props[propsKey] != nextProps[propsKey]){
this.isNeedUpdate = true;
break;
if(propsKey == "iconName"){
this.setState({
currentIconName: nextProps[propsKey]
});
break;
}
}
}
for (let stateKey in this.state) {
@ -98,11 +103,13 @@ class IconButton extends React.Component{
<StyledOuter
size={this.props.size}
isDisabled={this.props.isDisabled}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
onMouseDown={this.onMouseDown}
onMouseUp={this.onMouseUp}
isClickable={typeof this.props.onClick === 'function'}
>
{React.createElement(Icons[this.state.currentIconName], {size: "scale", color: this.state.currentIconColor, isfill: this.props.isFill})}
</StyledOuter>

View File

@ -71,7 +71,7 @@ const InputBlock = React.forwardRef((props, ref) => {
}
const onIconClick = (e) => {
props.onIconClick && props.onIconClick(e, value);
props.onIconClick(e, value);
}
return (
@ -111,7 +111,7 @@ const InputBlock = React.forwardRef((props, ref) => {
iconName={props.iconName}
isFill={props.isIconFill}
isDisabled={props.isDisabled}
onClick={onIconClick} />
onClick={typeof props.onIconClick == 'function' ? onIconClick : undefined } />
</StyledIconBlock>
</InputGroupAddon>
}

View File

@ -3,14 +3,13 @@ import PropTypes from "prop-types";
import { Text } from '../text';
const Label = (props) => {
const { isRequired, error, title, truncate, isInline, htmlFor} = props;
const { isRequired, error, title, truncate, isInline, htmlFor, text, display} = props;
const errorProp = error ? {color: "#c30"} : {}
const displayProp = isInline ? {} : {display : 'block'}
console.log("Label render");
//console.log("Label render");
return (
<Text.Body as='label' htmlFor={htmlFor} style={displayProp} {...errorProp} fontWeight={600} truncate={truncate} title={title}>
{props.children} {isRequired && " *"}
<Text.Body as='label' htmlFor={htmlFor} isInline={isInline} display={display} {...errorProp} fontWeight={600} truncate={truncate} title={title}>
{text} {isRequired && " *"}
</Text.Body>
);
}
@ -21,13 +20,15 @@ Label.propTypes = {
isInline: PropTypes.bool,
title: PropTypes.string,
truncate: PropTypes.bool,
htmlFor: PropTypes.string
htmlFor: PropTypes.string,
text: PropTypes.string,
display: PropTypes.string
};
Label.defaultProps = {
isRequired: false,
error: false,
isInline: true,
isInline: false,
truncate: false
};

View File

@ -12,6 +12,7 @@ import NavItem from './sub-components/nav-item'
class Layout extends React.Component {
constructor(props) {
super(props);
this.timeout = null;
this.state = this.mapPropsToState(props);
};
@ -119,12 +120,29 @@ class Layout extends React.Component {
});
};
handleNavHover = () => {
if(!this.state.isNavHoverEnabled) return;
handleNavMouseEnter = () => {
if (!this.state.isNavHoverEnabled) return;
this.timeout = setTimeout(() => {
this.setState({
isBackdropVisible: false,
isNavOpened: true,
isAsideVisible: false
});
}, 300);
}
handleNavMouseLeave = () => {
if (!this.state.isNavHoverEnabled) return;
if (this.timeout != null) {
clearTimeout(this.timeout);
this.timeout = null;
}
this.setState({
isBackdropVisible: false,
isNavOpened: !this.state.isNavOpened,
isNavOpened: false,
isAsideVisible: false
});
}
@ -139,7 +157,7 @@ class Layout extends React.Component {
};
render() {
console.log("Layout render");
//console.log("Layout render");
return (
<>
@ -167,8 +185,8 @@ class Layout extends React.Component {
this.state.isNavAvailable &&
<Nav
opened={this.state.isNavOpened}
onMouseEnter={this.handleNavHover}
onMouseLeave={this.handleNavHover}
onMouseEnter={this.handleNavMouseEnter}
onMouseLeave={this.handleNavMouseLeave}
>
<NavLogoItem
opened={this.state.isNavOpened}

View File

@ -17,7 +17,7 @@ const StyledAside = styled.aside`
`;
const Aside = React.memo(props => {
console.log("Aside render");
//console.log("Aside render");
const { visible, children } = props;
return (

View File

@ -20,7 +20,7 @@ const StyledNav = styled.nav`
`;
const HeaderNav = React.memo(props => {
console.log("HeaderNav render");
//console.log("HeaderNav render");
return (
<StyledNav>
{

View File

@ -20,7 +20,7 @@ const StyledHeader = styled.header`
`;
const Header = React.memo(props => {
console.log("Header render");
//console.log("Header render");
return (
<StyledHeader>
<NavItem

View File

@ -16,7 +16,7 @@ const StyledMain = styled.main`
`;
const Main = React.memo(props => {
console.log("Main render");
//console.log("Main render");
return (<StyledMain {...props}/>);
});

View File

@ -42,7 +42,7 @@ const NavItemBadge = styled(Badge)`
`;
const NavItem = React.memo(props => {
console.log("NavItem render");
//console.log("NavItem render");
const { seporator, opened, active, iconName, children, badgeNumber, onClick, onBadgeClick } = props;
const color = active ? activeColor : baseColor;

View File

@ -12,7 +12,7 @@ const LogoItem = styled.div`
`;
const NavLogoItem = React.memo(props => {
console.log("NavLogoItem render");
//console.log("NavLogoItem render");
const navLogoIconStyle = {
display: props.opened ? 'none' : 'block'
};

View File

@ -27,7 +27,7 @@ const StyledScrollbar = styled(Scrollbar)`
`;
const Nav = React.memo(props => {
console.log("Nav render");
//console.log("Nav render");
const { opened, onMouseEnter, onMouseLeave, children } = props;
return (

View File

@ -68,7 +68,7 @@ class ProfileActions extends React.PureComponent {
}
render() {
console.log("Layout sub-component ProfileActions render");
//console.log("Layout sub-component ProfileActions render");
return (
<div ref={this.ref}>
<Avatar

View File

@ -1,136 +1,103 @@
import React from 'react';
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import { Text } from '../text';
import React from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";
import { Text } from "../text";
const SimpleLink = ({ rel, isBold, fontSize, isTextOverflow,
isHovered, isSemitransparent, type, color, title, onClick,
...props }) => <a {...props}></a>;
const SimpleLink = ({
rel,
isBold,
fontSize,
isTextOverflow,
isHovered,
isSemitransparent,
type,
color,
title,
...props
}) => <a {...props} />;
const opacityCss = css`
opacity: ${props =>
(props.isSemitransparent && '0.5')};
`;
const getColor = color => {
switch (color) {
case 'gray':
return '#A3A9AE';
case 'blue':
return '#316DAA';
default:
return '#333333';
}
}
const colorCss = css`
color: ${props => getColor(props.color)};
color: ${props => props.color};
`;
const hoveredCss = css`
${colorCss};
border-bottom: ${props => (props.type === 'action' ? '1px dotted;' : 'none')};
text-decoration: ${props => (props.type === 'page' ? 'underline' : 'none')};
${colorCss};
border-bottom: ${props => (props.type === 'action' ? '1px dashed;' : 'none')};
text-decoration: ${props => (props.type === 'page' ? 'underline' : 'none')};
`;
const visitedCss = css`
${colorCss};
`;
const StyledLink = styled(SimpleLink)`
text-decoration: none;
user-select: none;
cursor: pointer;
opacity: ${props => props.isSemitransparent && "0.5"};
const dottedCss = css`
border-bottom: 1px dotted;
`;
line-height: calc(100% + 6px);
${colorCss};
const StyledLink = styled(SimpleLink).attrs((props) => ({
href: props.href,
rel: props.target === '_blank' && 'noopener noreferrer',
}))`
${opacityCss};
text-decoration: none;
user-select: none;
&:hover {
cursor: pointer;
${hoveredCss};
}
&:hover {
${hoveredCss};
}
&:visited {
${visitedCss};
}
&:not([href]):not([tabindex]) {
${colorCss};
text-decoration: none;
&:hover {
${hoveredCss};
}
}
${props => (props.isHovered && hoveredCss)}
${props => (props.type === 'action' && props.isHovered &&
dottedCss)}
${props => (props.isTextOverflow && css`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`)}
${props => props.isHovered && hoveredCss}
`;
const Link = props => {
const {
isBold,
title,
fontSize,
color,
isTextOverflow
} = props;
const { isBold, title, fontSize, color } = props;
//console.log("Link render", props);
const onClick = (e) => {
!props.href && e.preventDefault();
props.onClick && props.onClick(e);
}
console.log("Link render");
return (
<StyledLink {...props}>
<Text.Body
as="span"
color={getColor(color)}
fontSize={fontSize}
onClick={onClick}
isBold={isBold}
title={title}
>
{props.children}
</Text.Body>
</StyledLink>
);
}
return (
<StyledLink {...props}>
<Text.Body
as="span"
color={color}
fontSize={fontSize}
isBold={isBold}
title={title}
truncate={isTextOverflow}
>
{props.children}
</Text.Body>
</StyledLink>
);
};
Link.propTypes = {
color: PropTypes.oneOf(['gray', 'black', 'blue']),
fontSize: PropTypes.number,
href: PropTypes.string,
isBold: PropTypes.bool,
isHovered: PropTypes.bool,
isSemitransparent: PropTypes.bool,
isTextOverflow: PropTypes.bool,
onClick: PropTypes.func,
target: PropTypes.oneOf(['_blank', '_self', '_parent', '_top']),
text: PropTypes.string,
title: PropTypes.string,
type: PropTypes.oneOf(['action', 'page'])
color: PropTypes.string,
fontSize: PropTypes.number,
href: PropTypes.string,
isBold: PropTypes.bool,
isHovered: PropTypes.bool,
isSemitransparent: PropTypes.bool,
isTextOverflow: PropTypes.bool,
onClick: PropTypes.func,
rel: PropTypes.string,
tabIndex: PropTypes.number,
target: PropTypes.oneOf(["_blank", "_self", "_parent", "_top"]),
title: PropTypes.string,
type: PropTypes.oneOf(["action", "page"]),
};
Link.defaultProps = {
color: 'black',
fontSize: 13,
href: undefined,
isBold: false,
isHovered: false,
isSemitransparent: false,
isTextOverflow: true,
type: 'page'
}
color: "#333333",
fontSize: 13,
href: undefined,
isBold: false,
isHovered: false,
isSemitransparent: false,
isTextOverflow: true,
rel: "noopener noreferrer",
tabIndex: -1,
type: "page",
};
export default Link;

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