This commit is contained in:
Nikita Gopienko 2019-08-30 15:55:02 +03:00
commit 0070d6d31c
43 changed files with 455 additions and 220 deletions

View File

@ -63,7 +63,11 @@ namespace ASC.Api.Core.Middleware
Response = response;
Total = total;
if (response is IEnumerable<object> collection)
if (response is List<object> list)
{
Count = list.Count;
}
else if (response is IEnumerable<object> collection)
{
Count = collection.Count();
}

View File

@ -59,7 +59,7 @@ namespace ASC.Web.Api.Models
if (Id != Guid.Empty)
{
var profileUrl = CommonLinkUtility.GetUserProfile(userInfo.Tenant, Id, false);
var profileUrl = CommonLinkUtility.GetUserProfile(userInfo, false);
ProfileUrl = CommonLinkUtility.GetFullAbsolutePath(httpContext.HttpContext, profileUrl);
}
}

View File

@ -23,6 +23,8 @@
*
*/
using Microsoft.AspNetCore.Http;
namespace ASC.Collections
{
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
@ -35,12 +37,15 @@ namespace ASC.Collections
{
Value = value;
}
}
}
public HttpRequestDictionary(string baseKey)
HttpContext HttpContext { get; set; }
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
condition = (T) => true;
this.baseKey = baseKey;
this.baseKey = baseKey;
HttpContext = httpContext;
}
protected override void InsertRootKey(string rootKey)
@ -50,25 +55,25 @@ namespace ASC.Collections
public override void Reset(string rootKey, string key)
{
if (Common.HttpContext.Current != null)
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootKey);
Common.HttpContext.Current.Items[builtkey] = null;
HttpContext.Items[builtkey] = null;
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (Common.HttpContext.Current != null)
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootkey);
Common.HttpContext.Current.Items[builtkey] = new CachedItem(newValue);
HttpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return Common.HttpContext.Current?.Items[fullKey];
return HttpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)

View File

@ -156,16 +156,10 @@ namespace ASC.Common.Data
var fieldCount = reader.FieldCount;
while (reader.Read())
{
var row = new object[fieldCount];
for (var i = 0; i < fieldCount; i++)
{
row[i] = reader[i];
if (DBNull.Value.Equals(row[i])) row[i] = null;
}
result.Add(row);
result.Add(GetData(reader, fieldCount));
}
return result;
}
}
public static T ExecuteScalar<T>(this DbCommand command)
{
@ -253,6 +247,20 @@ namespace ASC.Common.Data
}
return result;
}
public static List<T> ExecuteList<T>(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect, Converter<object[], T> mapper)
{
ApplySqlInstruction(command, sql, dialect);
var result = new List<T>();
using (var reader = command.ExecuteReader())
{
var fieldCount = reader.FieldCount;
while (reader.Read())
{
result.Add(mapper(GetData(reader, fieldCount)));
}
}
return result;
}
public static T ExecuteScalar<T>(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect)
{
@ -323,6 +331,18 @@ namespace ASC.Common.Data
command.AddParameters(parameters);
}
return command;
}
private static object[] GetData(IDataRecord reader, int fieldCount)
{
var row = new object[fieldCount];
for (var i = 0; i < fieldCount; i++)
{
row[i] = reader[i];
if (DBNull.Value.Equals(row[i])) row[i] = null;
}
return row;
}
}
}

View File

@ -240,6 +240,11 @@ namespace ASC.Common.Data
return Command.ExecuteList(sql, GetDialect(), converter);
}
public List<T> ExecuteList<T>(ISqlInstruction sql, Converter<object[], T> converter)
{
return Command.ExecuteList(sql, GetDialect(), converter);
}
public T ExecuteScalar<T>(string sql, params object[] parameters)
{
return Command.ExecuteScalar<T>(sql, parameters);
@ -368,6 +373,11 @@ namespace ASC.Common.Data
}
public List<T> ExecuteList<T>(ISqlInstruction sql, Converter<IDataRecord, T> converter)
{
return dbManager.ExecuteList(sql, converter);
}
public List<T> ExecuteList<T>(ISqlInstruction sql, Converter<object[], T> converter)
{
return dbManager.ExecuteList<T>(sql, converter);
}

View File

@ -51,7 +51,9 @@ namespace ASC.Common.Data
Task<List<object[]>> ExecuteListAsync(ISqlInstruction sql);
List<T> ExecuteList<T>(ISqlInstruction sql, Converter<IDataRecord, T> converter);
List<T> ExecuteList<T>(ISqlInstruction sql, Converter<IDataRecord, T> converter);
List<T> ExecuteList<T>(ISqlInstruction sql, Converter<object[], T> converter);
T ExecuteScalar<T>(string sql, params object[] parameters);

View File

@ -131,6 +131,11 @@ namespace ASC.Common.Data
}
public List<T> ExecuteList<T>(ISqlInstruction sql, Converter<IDataRecord, T> converter)
{
return databases.SelectMany(db => db.ExecuteList(sql, converter)).ToList();
}
public List<T> ExecuteList<T>(ISqlInstruction sql, Converter<object[], T> converter)
{
return databases.SelectMany(db => db.ExecuteList(sql, converter)).ToList();
}
@ -172,6 +177,6 @@ namespace ASC.Common.Data
public IDbTransaction BeginTransaction()
{
return localDb.BeginTransaction();
}
}
}
}

View File

@ -91,7 +91,7 @@ namespace ASC.Core.Caching
}
}
public IDictionary<Guid, UserInfo> GetUsers(int tenant, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
public IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
{
return service.GetUsers(tenant, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text, sortBy, sortOrderAsc, limit, offset, out total);
}

View File

@ -27,17 +27,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ASC.Collections;
using ASC.Common.DependencyInjection;
using ASC.Core.Caching;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Core.Users;
using Microsoft.AspNetCore.Http;
namespace ASC.Core
{
public class UserManager
{
private readonly IUserService userService;
private readonly IDictionary<Guid, UserInfo> systemUsers;
private readonly IDictionary<Guid, UserInfo> systemUsers;
private readonly IHttpContextAccessor Accessor;
public UserManager(IUserService service)
@ -47,7 +52,8 @@ namespace ASC.Core
systemUsers = Configuration.Constants.SystemAccounts.ToDictionary(a => a.ID, a => new UserInfo { ID = a.ID, LastName = a.Name });
systemUsers[Constants.LostUser.ID] = Constants.LostUser;
systemUsers[Constants.OutsideUser.ID] = Constants.OutsideUser;
systemUsers[Constants.NamingPoster.ID] = Constants.NamingPoster;
systemUsers[Constants.NamingPoster.ID] = Constants.NamingPoster;
Accessor = CommonServiceProvider.GetService<IHttpContextAccessor>();
}
@ -89,7 +95,7 @@ namespace ASC.Core
public IEnumerable<UserInfo> GetUsers(int tenantId, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
{
return userService.GetUsers(tenantId, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text, sortBy, sortOrderAsc, limit, offset, out total).Values;
return userService.GetUsers(tenantId, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text, sortBy, sortOrderAsc, limit, offset, out total);
}
public DateTime GetMaxUsersLastModified(int tenantId)
@ -151,7 +157,12 @@ namespace ASC.Core
public bool UserExists(int tenantId, Guid id)
{
return !GetUsers(tenantId, id).Equals(Constants.LostUser);
return !UserExists(GetUsers(tenantId, id));
}
public bool UserExists(UserInfo user)
{
return !user.Equals(Constants.LostUser);
}
public bool IsSystemUser(Guid id)
@ -258,23 +269,30 @@ namespace ASC.Core
return GetUsers(tenantId, id).GetUserGroupsId(tenantId);
}
public GroupInfo[] GetUserGroups(Tenant tenant, Guid id)
public List<GroupInfo> GetUserGroups(Tenant tenant, Guid id)
{
return GetUsers(tenant.TenantId, id).GetGroups(tenant, IncludeType.Distinct, Guid.Empty);
}
public GroupInfo[] GetUserGroups(Tenant tenant, Guid id, Guid categoryID)
public List<GroupInfo> GetUserGroups(Tenant tenant, Guid id, Guid categoryID)
{
return GetUsers(tenant.TenantId, id).GetGroups(tenant, IncludeType.Distinct, categoryID);
}
public GroupInfo[] GetUserGroups(Tenant tenant, Guid userID, IncludeType includeType)
public List<GroupInfo> GetUserGroups(Tenant tenant, Guid userID, IncludeType includeType)
{
return GetUsers(tenant.TenantId, userID).GetGroups(tenant, includeType, null);
}
}
internal List<GroupInfo> GetUserGroups(Tenant tenant, Guid userID, IncludeType includeType, Guid? categoryId)
{
var httpRequestDictionary = new HttpRequestDictionary<List<GroupInfo>>(Accessor?.HttpContext, "GroupInfo");
var fromCache = httpRequestDictionary.Get(userID.ToString());
if (fromCache != null)
{
return fromCache;
}
internal GroupInfo[] GetUserGroups(Tenant tenant, Guid userID, IncludeType includeType, Guid? categoryId)
{
var result = new List<GroupInfo>();
var distinctUserGroups = new List<GroupInfo>();
@ -302,12 +320,21 @@ namespace ASC.Core
}
result.Sort((group1, group2) => string.Compare(group1.Name, group2.Name, StringComparison.Ordinal));
return result.ToArray();
httpRequestDictionary.Add(userID.ToString(), result);
return result;
}
internal IEnumerable<Guid> GetUserGroupsGuids(int tenantId, Guid userID)
{
{
var httpRequestDictionary = new HttpRequestDictionary<List<Guid>>(Accessor?.HttpContext, "GroupInfoID");
var fromCache = httpRequestDictionary.Get(userID.ToString());
if (fromCache != null)
{
return fromCache;
}
var result = new List<Guid>();
var refs = GetRefsInternal(tenantId);
@ -324,7 +351,9 @@ namespace ASC.Core
.Select(r => r.GroupId);
result.AddRange(toAdd);
}
}
}
httpRequestDictionary.Add(userID.ToString(), result);
return result;
}
@ -350,7 +379,7 @@ namespace ASC.Core
userService.SaveUserGroupRef(tenant.TenantId, new UserGroupRef(userId, groupId, UserGroupRefType.Contains));
GetUsers(tenant.TenantId, userId).ResetGroupCache();
ResetGroupCache(userId);
}
public void RemoveUserFromGroup(Tenant tenant, Guid userId, Guid groupId)
@ -360,14 +389,20 @@ namespace ASC.Core
userService.RemoveUserGroupRef(tenant.TenantId, userId, groupId, UserGroupRefType.Contains);
GetUsers(tenant.TenantId, userId).ResetGroupCache();
}
ResetGroupCache(userId);
}
internal void ResetGroupCache(Guid userID)
{
new HttpRequestDictionary<List<GroupInfo>>(Accessor?.HttpContext, "GroupInfo").Reset(userID.ToString());
new HttpRequestDictionary<List<Guid>>(Accessor?.HttpContext, "GroupInfoID").Reset(userID.ToString());
}
#endregion Users
#region Company
public GroupInfo[] GetDepartments(int tenantId)
{
return GetGroups(tenantId);

View File

@ -34,7 +34,7 @@ namespace ASC.Core
{
IDictionary<Guid, UserInfo> GetUsers(int tenant, DateTime from);
IDictionary<Guid, UserInfo> GetUsers(int tenant, bool isAdmin,
IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin,
EmployeeStatus? employeeStatus,
List<List<Guid>> includeGroups,
List<Guid> excludeGroups,

View File

@ -29,7 +29,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using ASC.Collections;
using ASC.Core.Tenants;
using ASC.Notify.Recipients;
@ -38,13 +37,10 @@ namespace ASC.Core.Users
[Serializable]
public sealed class UserInfo : IDirectRecipient, ICloneable
{
private readonly HttpRequestDictionary<GroupInfo[]> groupCache = new HttpRequestDictionary<GroupInfo[]>("UserInfo-Groups");
private readonly HttpRequestDictionary<IEnumerable<Guid>> groupCacheId = new HttpRequestDictionary<IEnumerable<Guid>>("UserInfo-Groups1");
public UserInfo()
{
Status = EmployeeStatus.Active;
ActivationStatus = EmployeeActivationStatus.NotActivated;
ActivationStatus = EmployeeActivationStatus.NotActivated;
Contacts = new List<string>();
LastModified = DateTime.UtcNow;
}
@ -72,8 +68,8 @@ namespace ASC.Core.Users
public DateTime? WorkFromDate { get; set; }
public string Email { get; set; }
public string Email { get; set; }
public List<string> Contacts { get; set; }
public string Location { get; set; }
@ -150,13 +146,14 @@ namespace ASC.Core.Users
return MemberwiseClone();
}
internal GroupInfo[] GetGroups(Tenant tenant, IncludeType includeType, Guid? categoryId)
internal List<GroupInfo> GetGroups(Tenant tenant, IncludeType includeType, Guid? categoryId)
{
var groups = groupCache.Get(ID.ToString(), () => CoreContext.UserManager.GetUserGroups(tenant, ID, IncludeType.Distinct, null));
var groups = CoreContext.UserManager.GetUserGroups(tenant, ID, IncludeType.Distinct, null);
if (categoryId.HasValue)
{
return groups.Where(r => r.CategoryID.Equals(categoryId.Value)).ToArray();
return groups.Where(r => r.CategoryID.Equals(categoryId.Value)).ToList();
}
return groups;
@ -164,12 +161,7 @@ namespace ASC.Core.Users
internal IEnumerable<Guid> GetUserGroupsId(int tenantId)
{
return groupCacheId.Get(ID.ToString(), () => CoreContext.UserManager.GetUserGroupsGuids(tenantId, ID));
}
internal void ResetGroupCache()
{
groupCache.Reset(ID.ToString());
return CoreContext.UserManager.GetUserGroupsGuids(tenantId, ID);
}
internal string ContactsToString()

View File

@ -50,7 +50,7 @@ namespace ASC.Core.Data
return ExecList(q).ConvertAll(ToUser).ToDictionary(u => u.ID);
}
public IDictionary<Guid, UserInfo> GetUsers(int tenant, bool isAdmin,
public IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin,
EmployeeStatus? employeeStatus,
List<List<Guid>> includeGroups,
List<Guid> excludeGroups,
@ -84,8 +84,8 @@ namespace ASC.Core.Data
{
q.SetFirstResult((int)offset);
}
return ExecList(q).ConvertAll(ToUser).ToDictionary(u => u.ID);
return GetDb().ExecuteList(q, ToUser);
}
private SqlQuery GetUserQueryForFilter(SqlQuery q, bool isAdmin,

View File

@ -65,6 +65,7 @@ namespace ASC.Data.Reassigns
public double Percentage { get; set; }
public bool IsCompleted { get; set; }
public Guid FromUser { get; }
public UserInfo User { get; }
public MessageService MessageService { get; }
public StudioNotifyService StudioNotifyService { get; }
@ -77,6 +78,7 @@ namespace ASC.Data.Reassigns
_httpHeaders = QueueWorker.GetHttpHeaders(context.Request);
_tenantId = tenantId;
User = user;
FromUser = user.ID;
_userName = UserFormatter.GetUserName(user, DisplayUserNameFormat.Default);
_currentUserId = currentUserId;
@ -223,7 +225,7 @@ namespace ASC.Data.Reassigns
private void SendSuccessNotify(long docsSpace, long crmSpace, long mailSpace, long talkSpace)
{
if (_notify)
StudioNotifyService.SendMsgRemoveUserDataCompleted(_tenantId, _currentUserId, FromUser, _userName,
StudioNotifyService.SendMsgRemoveUserDataCompleted(_tenantId, _currentUserId, User, _userName,
docsSpace, crmSpace, mailSpace, talkSpace);
if (_httpHeaders != null)
@ -236,7 +238,7 @@ namespace ASC.Data.Reassigns
{
if (!_notify) return;
StudioNotifyService.SendMsgRemoveUserDataFailed(_tenantId, _currentUserId, FromUser, _userName, errorMessage);
StudioNotifyService.SendMsgRemoveUserDataFailed(_tenantId, _currentUserId, User, _userName, errorMessage);
}
}
}

View File

@ -99,7 +99,7 @@ class ArticleBodyContent extends React.Component {
defaultExpandAll={true}
switcherIcon={this.switcherIcon}
onSelect={this.onSelect}
defaultSelectedKeys={selectedKeys}
selectedKeys={selectedKeys}
>
{getItems(data)}
</TreeMenu>

View File

@ -100,33 +100,33 @@ class SectionBodyContent extends React.PureComponent {
return [
{
key: "send-email",
label: t("PeopleResource:LblSendEmail"),
label: t("LblSendEmail"),
onClick: this.onEmailSentClick
},
{
key: "send-message",
label: t("PeopleResource:LblSendMessage"),
label: t("LblSendMessage"),
onClick: this.onSendMessageClick
},
{ key: "key3", isSeparator: true },
{
key: "edit",
label: t("PeopleResource:LblEdit"),
label: t("EditButton"),
onClick: this.onEditClick.bind(this, user)
},
{
key: "change-password",
label: t("PeopleResource:LblChangePassword"),
label: t("PasswordChangeButton"),
onClick: this.onChangePasswordClick
},
{
key: "change-email",
label: t("PeopleResource:LblChangeEmail"),
label: t("EmailChangeButton"),
onClick: this.onChangeEmailClick
},
{
key: "disable",
label: t("PeopleResource:DisableUserButton"),
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user)
}
];
@ -134,22 +134,22 @@ class SectionBodyContent extends React.PureComponent {
return [
{
key: "enable",
label: t("PeopleResource:EnableUserButton"),
label: t("EnableUserButton"),
onClick: this.onEnableClick.bind(this, user)
},
{
key: "reassign-data",
label: t("PeopleResource:LblReassignData"),
label: t("ReassignData"),
onClick: this.onReassignDataClick
},
{
key: "delete-personal-data",
label: t("PeopleResource:LblRemoveData"),
label: t("RemoveData"),
onClick: this.onDeletePersonalDataClick.bind(this, user)
},
{
key: "delete-profile",
label: t("PeopleResource:LblDeleteProfile"),
label: t("DeleteSelfProfile"),
onClick: this.onDeleteProfileClick
}
];
@ -157,27 +157,27 @@ class SectionBodyContent extends React.PureComponent {
return [
{
key: "edit",
label: t("PeopleResource:LblEdit"),
label: t("EditButton"),
onClick: this.onEditClick.bind(this, user)
},
{
key: "invite-again",
label: "Invite again",
label: t("LblInviteAgain"),
onClick: this.onInviteAgainClick
},
user.status === EmployeeStatus.Active
? {
key: "disable",
label: t("PeopleResource:DisableUserButton"),
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user)
} : {
key: "enable",
label: t("PeopleResource:EnableUserButton"),
label: t("EnableUserButton"),
onClick: this.onEnableClick.bind(this, user)
},
{
key: "delete-profile",
label: t("PeopleResource:LblDeleteProfile"),
label: t("DeleteSelfProfile"),
onClick: this.onDeleteProfileClick
}
];
@ -235,13 +235,13 @@ class SectionBodyContent extends React.PureComponent {
<EmptyScreenContainer
imageSrc="images/empty_screen_filter.png"
imageAlt="Empty Screen Filter image"
headerText={t("PeopleResource:NotFoundTitle")}
descriptionText={t("PeopleResource:NotFoundDescription")}
headerText={t("NotFoundTitle")}
descriptionText={t("NotFoundDescription")}
buttons={
<>
<Icons.CrossIcon size="small" style={{ marginRight: "4px" }} />
<Link type="action" isHovered={true} onClick={this.onResetFilter}>
{t("PeopleResource:ClearButton")}
{t("ClearButton")}
</Link>
</>
}

View File

@ -3,6 +3,8 @@ import { withRouter } from "react-router";
import { RowContent, Link, Icons } from "asc-web-components";
import { connect } from "react-redux";
import { getUserStatus } from "../../../../../store/people/selectors";
import { useTranslation } from 'react-i18next';
import { headOfDepartment } from './../../../../../helpers/customNames';
const UserContent = ({ user, history, settings }) => {
const { userName, displayName, headDepartment, department, mobilePhone, email } = user;
@ -35,6 +37,7 @@ const UserContent = ({ user, history, settings }) => {
const nameColor = status === 'pending' ? '#A3A9AE' : '#333333';
const sideInfoColor = status === 'pending' ? '#D0D5DA' : '#A3A9AE';
const t = useTranslation();
return (
<RowContent>
@ -44,7 +47,7 @@ const UserContent = ({ user, history, settings }) => {
{status === 'disabled' && <Icons.CatalogSpamIcon size='small' isfill={true} color='#3B72A7' />}
</>
{headDepartment
? <Link type='page' title='Head of department' fontSize={12} color={sideInfoColor} onClick={onHeadDepartmentClick} >Head of department</Link>
? <Link type='page' title={t('CustomHeadOfDepartment', { headOfDepartment })} fontSize={12} color={sideInfoColor} onClick={onHeadDepartmentClick} >{t('CustomHeadOfDepartment', { headOfDepartment })}</Link>
: <></>
}
<Link type='action' title={department} fontSize={12} color={sideInfoColor} onClick={onDepartmentClick} >{department}</Link>

View File

@ -6,11 +6,12 @@ import find from "lodash/find";
import result from "lodash/result";
import { isAdmin } from "../../../../../store/auth/selectors";
import { useTranslation } from "react-i18next";
import { typeGuest, typeUser, departmentName } from './../../../../../helpers/customNames';
const getSortData = () => {
const getSortData = ( t ) => {
return [
{ key: "firstname", label: "By first name" },
{ key: "lastname", label: "By last name" }
{ key: "firstname", label: t('ByFirstNameSorting') },
{ key: "lastname", label: t('ByLastNameSorting') }
];
};
@ -58,7 +59,7 @@ const getGroup = filterValues => {
return groupId || null;
};
const SectionFilterContent = ({
const SectionFilterContent = React.memo(({
fetchPeople,
filter,
onLoading,
@ -109,18 +110,18 @@ const SectionFilterContent = ({
{
key: "filter-status",
group: "filter-status",
label: t("PeopleResource:LblStatus"),
label: t("UserStatus"),
isHeader: true
},
{
key: "1",
group: "filter-status",
label: t("PeopleResource:LblActive")
label: t("LblActive")
},
{
key: "2",
group: "filter-status",
label: t("PeopleResource:LblTerminated")
label: t("LblTerminated")
}
];
@ -133,31 +134,35 @@ const SectionFilterContent = ({
{
key: "filter-email",
group: "filter-email",
label: t("PeopleResource:Email"),
label: t("Email"),
isHeader: true
},
{ key: "1", group: "filter-email", label: t("PeopleResource:LblActive") },
{
key: "1",
group: "filter-email",
label: t("LblActive")
},
{
key: "2",
group: "filter-email",
label: t("PeopleResource:LblPending")
label: t("LblPending")
},
{
key: "filter-type",
group: "filter-type",
label: t("PeopleResource:LblByType"),
label: t("UserType"),
isHeader: true
},
{ key: "admin", group: "filter-type", label: "Administrator"},
{ key: "user", group: "filter-type", label: "User" },
{ key: "guest", group: "filter-type", label: "Guest" },
{ key: "admin", group: "filter-type", label: t("Administrator")},
{ key: "user", group: "filter-type", label: t('CustomTypeUser', { typeUser })},
{ key: "guest", group: "filter-type", label: t('CustomTypeGuest', { typeGuest }) },
{
key: "filter-other",
group: "filter-other",
label: t("PeopleResource:LblOther"),
label: t("LblOther"),
isHeader: true
},
{ key: "filter-type-group", group: "filter-other", subgroup: 'filter-group', label: "Group" },
{ key: "filter-type-group", group: "filter-other", subgroup: 'filter-group', label: t('CustomDepartmentName', { departmentName }) },
...groupOptions
];
@ -165,7 +170,7 @@ const SectionFilterContent = ({
return filterOptions;
}, [user, t, groups]);
}, [user, groups, t]);
const onFilter = useCallback(
data => {
@ -187,16 +192,15 @@ const SectionFilterContent = ({
},
[onLoading, fetchPeople, filter]
);
return (
<FilterInput
getFilterData={getData}
getSortData={getSortData}
getSortData={()=> getSortData(t)}
selectedFilterData={selectedFilterData}
onFilter={onFilter}
/>
);
};
});
function mapStateToProps(state) {
return {

View File

@ -6,17 +6,18 @@ import { isAdmin } from '../../../../../store/auth/selectors';
import { withTranslation } from 'react-i18next';
import { updateUserStatus, updateUserType } from '../../../../../store/people/actions';
import { EmployeeStatus, EmployeeType } from '../../../../../helpers/constants';
import { typeUser , typeGuest } from '../../../../../helpers/../helpers/customNames';
const contextOptions = () => {
const contextOptions = ( t ) => {
return [
{
key: "edit-group",
label: "Edit",
label: t("EditButton"),
onClick: toastr.success.bind(this, "Edit group action")
},
{
key: "delete-group",
label: "Delete",
label: t('DeleteButton'),
onClick: toastr.success.bind(this, "Delete group action")
}
];
@ -27,7 +28,7 @@ const wrapperStyle = {
alignItems: "center"
};
const SectionHeaderContent = ({
const SectionHeaderContent = React.memo(({
isHeaderVisible,
isHeaderIndeterminate,
isHeaderChecked,
@ -46,70 +47,70 @@ const SectionHeaderContent = ({
const onSetActive = useCallback(() => {
updateUserStatus(EmployeeStatus.Active, selectedUserIds);
toastr.success("Set active action");
}, [selectedUserIds, updateUserStatus]);
toastr.success(t('SuccessChangeUserStatus'));
}, [selectedUserIds, updateUserStatus, t]);
const onSetDisabled = useCallback(() => {
updateUserStatus(EmployeeStatus.Disabled, selectedUserIds);
toastr.success("Set disabled action");
}, [selectedUserIds, updateUserStatus]);
toastr.success(t('SuccessChangeUserStatus'));
}, [selectedUserIds, updateUserStatus, t]);
const onSetEmployee = useCallback(() => {
updateUserType(EmployeeType.User, selectedUserIds);
toastr.success("Set user(s) as employees");
}, [selectedUserIds, updateUserType]);
toastr.success(t('SuccessChangeUserType'));
}, [selectedUserIds, updateUserType, t]);
const onSetGuest = useCallback(() => {
updateUserType(EmployeeType.Guest, selectedUserIds);
toastr.success("Set user(s) as guests");
}, [selectedUserIds, updateUserType]);
toastr.success(t('SuccessChangeUserType'));
}, [selectedUserIds, updateUserType, t]);
const menuItems = [
{
label: "Select",
label: t('LblSelect'),
isDropdown: true,
isSeparator: true,
isSelect: true,
fontWeight: "bold",
children: [
<DropDownItem key="active" label="Active" />,
<DropDownItem key="disabled" label="Disabled" />,
<DropDownItem key="invited" label="Invited" />
<DropDownItem key="active" label={t('LblActive')} />,
<DropDownItem key="disabled" label={t('LblTerminated')} />,
<DropDownItem key="invited" label={t('LblInvited')} />
],
onSelect: (item) => onSelect(item.key)
},
{
label: "Make employee",
label: t('CustomMakeUser', { typeUser }),
disabled: !selection.length,
onClick: onSetEmployee
},
{
label: "Make guest",
label: t('CustomMakeGuest', { typeGuest }),
disabled: !selection.length,
onClick: onSetGuest
},
{
label: "Set active",
label: t('LblSetActive'),
disabled: !selection.length,
onClick: onSetActive
},
{
label: "Set disabled",
label: t('LblSetDisabled'),
disabled: !selection.length,
onClick: onSetDisabled
},
{
label: "Invite again",
label: t('LblInviteAgain'),
disabled: !selection.length,
onClick: toastr.success.bind(this, "Invite again action")
},
{
label: "Send e-mail",
label: t('LblSendEmail'),
disabled: !selection.length,
onClick: toastr.success.bind(this, "Send e-mail action")
},
{
label: t('PeopleResource:DeleteButton'),
label: t('DeleteButton'),
disabled: !selection.length,
onClick: toastr.success.bind(this, "Delete action")
}
@ -124,8 +125,8 @@ const SectionHeaderContent = ({
onChange={onCheck}
menuItems={menuItems}
visible={isHeaderVisible}
moreLabel="More"
closeTitle="Close"
moreLabel={t("More")}
closeTitle={t("CloseButton")}
onClose={onClose}
selected={menuItems[0].label}
/>
@ -137,18 +138,18 @@ const SectionHeaderContent = ({
{isAdmin &&
<ContextMenuButton
directionX='right'
title='Actions'
title={t("Actions")}
iconName='VerticalDotsIcon'
size={16}
color='#A3A9AE'
getData={contextOptions}
getData={() => contextOptions(t)}
isDisabled={false}/>
}
</div>
: <Text.ContentHeader>People</Text.ContentHeader>
: <Text.ContentHeader>{t("People")}</Text.ContentHeader>
)
);
};
});
const mapStateToProps = (state) => {
return {

View File

@ -77,15 +77,15 @@ const SectionPagingContent = ({
() => [
{
key: 25,
label: "25 per page"
label: t('CountPerPage', { count: 25 })
},
{
key: 50,
label: "50 per page"
label: t('CountPerPage', { count: 50 })
},
{
key: 100,
label: "100 per page"
label: t('CountPerPage', { count: 100 })
}
],
[]
@ -96,19 +96,19 @@ const SectionPagingContent = ({
const totalPages = Math.ceil(filter.total / filter.pageCount);
return [...Array(totalPages).keys()].map(
item => {
return { key: item, label: `${item+1} of ${totalPages}` };
return { key: item, label: t('PageOfTotalPage', { page: item+1, totalPage: totalPages }) };
}
);
}, [filter.total, filter.pageCount]);
}, [filter.total, filter.pageCount, t]);
const emptyPageSelection = {
key: 0,
label: '1 of 1'
label: t('PageOfTotalPage', { page: 1, totalPage: 1 })
}
const emptyCountSelection = {
key: 0,
label: "25 per page"
label: t('CountPerPage', { count: 25 })
};
const selectedPageItem = pageItems.find(x => x.key === filter.page) || emptyPageSelection;
@ -118,8 +118,8 @@ const SectionPagingContent = ({
return (
<Paging
previousLabel={t('UserControlsCommonResource:PreviousPage')}
nextLabel={t('UserControlsCommonResource:NextPage')}
previousLabel={t('PreviousPage')}
nextLabel={t('NextPage')}
pageItems={pageItems}
onSelectPage={onChangePage}
countItems={countItems}

View File

@ -0,0 +1,58 @@
import i18n from "i18next";
import Backend from "i18next-xhr-backend";
import config from "../../../../package.json";
const newInstance = i18n.createInstance();
if (process.env.NODE_ENV === "production") {
newInstance
.use(Backend)
.init({
lng: 'en',
fallbackLng: "en",
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: true
},
backend: {
loadPath: `${config.homepage}/locales/Home/{{lng}}/{{ns}}.json`
}
});
} else if (process.env.NODE_ENV === "development") {
const resources = {
en: {
translation: require("./locales/en/translation.json")
}
};
newInstance.init({
resources: resources,
lng: 'en',
fallbackLng: "en",
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: true
}
});
}
export default newInstance;

View File

@ -4,6 +4,9 @@ import PropTypes from "prop-types";
import { withRouter } from "react-router";
import { PageLayout, RequestLoader } from "asc-web-components";
import { withTranslation } from 'react-i18next';
import i18n from "./i18n";
import { I18nextProvider } from "react-i18next";
import {
ArticleHeaderContent,
ArticleBodyContent,
@ -98,13 +101,13 @@ class Home extends React.Component {
} = this.state;
const t = this.props.t;
return (
<>
<I18nextProvider i18n={i18n}>
<RequestLoader
visible={this.state.isLoading}
zIndex={256}
loaderSize={16}
loaderColor={"#999"}
label={`${t('Resource:LoadingProcessing')} ${t('Resource:LoadingDescription')}`}
label={`${t('LoadingProcessing')} ${t('LoadingDescription')}`}
fontSize={12}
fontColor={"#999"}
/>
@ -135,7 +138,7 @@ class Home extends React.Component {
<SectionPagingContent onLoading={this.onLoading} />
}
/>
</>
</I18nextProvider>
);
}
}

View File

@ -0,0 +1,51 @@
{
"LoadingProcessing": "Loading...",
"LblSendEmail": "Send email",
"LblSendMessage": "Send message",
"EditButton": "Edit",
"PasswordChangeButton": "Change password",
"EmailChangeButton": "Change email",
"DisableUserButton": "Disable",
"EnableUserButton": "Enable",
"ReassignData": "Reassign data",
"RemoveData": "Delete personal data",
"DeleteSelfProfile": "Delete profile",
"LoadingDescription": "Please wait...",
"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",
"ClearButton": "Reset filter",
"UserStatus": "Status",
"LblActive": "Active",
"LblTerminated": "Disabled",
"Email": "Email",
"LblPending": "Pending",
"UserType": "Type",
"Administrator": "Administrator",
"LblOther": "Other",
"DeleteButton": "Delete",
"SuccessChangeUserStatus": "The user status was successfully changed",
"SuccessChangeUserType": "The user type was successfully changed",
"LblSelect": "Select",
"More": "More",
"CloseButton": "Close",
"Actions": "Actions",
"People": "People",
"PreviousPage": "Previous",
"NextPage": "Next",
"LblInviteAgain": "Invite again",
"ByFirstNameSorting": "By first name",
"ByLastNameSorting": "By last name",
"LblInvited": "Invited",
"LblSetActive": "Set active",
"LblSetDisabled": "Set disabled",
"CustomHeadOfDepartment": " {{headOfDepartment}}",
"CustomTypeGuest": "{{typeGuest}}",
"CustomTypeUser": "{{typeUser}}",
"CustomMakeUser": "Make {{typeUser, lowercase}}",
"CustomMakeGuest": "Make {{typeGuest, lowercase}}",
"CustomDepartmentName": "{{departmentName}}" ,
"CountPerPage": "{{count}} per page",
"PageOfTotalPage": "{{page}} of {{totalPage}}"
}

View File

@ -1,7 +1,7 @@
import React, { useCallback } from "react";
import { withRouter } from "react-router";
import { useTranslation } from 'react-i18next';
import { departmentName, position, employedSinceDate } from '../../../../customNames';
import { departmentName, position, employedSinceDate } from '../../../../../helpers/customNames';
import {
Text,
Avatar,

View File

@ -10,7 +10,7 @@ import PasswordField from './FormFields/PasswordField'
import DateField from './FormFields/DateField'
import RadioField from './FormFields/RadioField'
import DepartmentField from './FormFields/DepartmentField'
import { departmentName, position, employedSinceDate } from '../../../../customNames';
import { departmentName, position, employedSinceDate } from '../../../../../helpers/customNames';
class CreateUserForm extends React.Component {

View File

@ -10,7 +10,7 @@ import TextChangeField from './FormFields/TextChangeField'
import DateField from './FormFields/DateField'
import RadioField from './FormFields/RadioField'
import DepartmentField from './FormFields/DepartmentField'
import { departmentName, position, employedSinceDate, guest, employee } from '../../../../customNames';
import { departmentName, position, employedSinceDate, typeGuest, typeUser } from '../../../../../helpers/customNames';
class UpdateUserForm extends React.Component {
@ -195,12 +195,12 @@ class UpdateUserForm extends React.Component {
radioOnChange={this.onTextChange}
/>
<RadioField
labelText={`${this.props.t("Type")}:`}
labelText={`${this.props.t("UserType")}:`}
radioName="sex"
radioValue={this.state.profile.isVisitor.toString()}
radioOptions={[
{ value: "true", label: this.props.t("CustomTypeGuest", { guest })},
{ value: "false", label: this.props.t("CustomTypeUser", { employee })}
{ value: "true", label: this.props.t("CustomTypeGuest", { typeGuest })},
{ value: "false", label: this.props.t("CustomTypeUser", { typeUser })}
]}
radioIsDisabled={this.state.isLoading}
radioOnChange={this.onTextChange}

View File

@ -11,7 +11,7 @@
"SaveButton": "Save",
"CancelButton": "Cancel",
"CopyEmailAndPassword": "Copy e-mail & password",
"Type": "Type",
"UserType": "Type",
"ActivationLink": "Activation link",
"AddPhoto": "Add photo",
@ -27,7 +27,6 @@
"CustomEmployedSinceDate": "{{employedSinceDate}}",
"CustomPosition": "{{position}}",
"CustomDepartmentName": "{{departmentName}}",
"CustomTypeGuest": "{{guest}}",
"CustomTypeUser": "{{employee}}"
"CustomTypeGuest": "{{typeGuest}}",
"CustomTypeUser": "{{typeUser}}"
}

View File

@ -1,5 +1,6 @@
export const departmentName = 'Department';
export const position = 'Position';
export const employedSinceDate = 'Employed since';
export const guest = 'Guest';
export const employee = 'Employee';
export const typeGuest = 'Guest';
export const typeUser = 'Employee';
export const headOfDepartment = 'Head of Department';

View File

@ -56,6 +56,15 @@
"RemoveData",
"DeleteSelfProfile",
"EditButton",
"UserStatus",
"Email",
"UserType",
"Administrator",
"DeleteButton",
"More",
"CloseButton",
"Actions",
"People",
"EnableUserButton"
],
"PeopleResource": [
@ -64,7 +73,21 @@
"NotFoundDescription",
"NotFoundTitle",
"ClearButton",
"LblActive",
"LblTerminated",
"LblPending",
"LblOther",
"LblChangeEmail"
],
"PeopleJSResource": [
"SuccessChangeUserStatus",
"SuccessChangeUserType"
],
"UserControlsCommonResource": [
"NextPage",
"PreviousPage",
"LblSelect"
]
}
},

View File

@ -45,7 +45,6 @@ namespace ASC.Employee.Core.Controllers
{
public Common.Logging.LogManager LogManager { get; }
public Tenant Tenant { get { return ApiContext.Tenant; } }
public ApiContext ApiContext { get; }
public MessageService MessageService { get; }
public QueueWorkerReassign QueueWorkerReassign { get; }
@ -256,8 +255,7 @@ namespace ASC.Employee.Core.Controllers
public IEnumerable<EmployeeWraperFull> GetFullByFilter(EmployeeStatus? employeeStatus, Guid? groupId, EmployeeActivationStatus? activationStatus, EmployeeType? employeeType, bool? isAdministrator)
{
var users = GetByFilter(employeeStatus, groupId, activationStatus, employeeType, isAdministrator);
return users.Select(u => new EmployeeWraperFull(u, ApiContext)).ToList();
return users.Select(u => new EmployeeWraperFull(u, ApiContext));
}
[Read("simple/filter")]
@ -767,10 +765,10 @@ namespace ASC.Employee.Core.Controllers
{
SecurityContext.DemandPermissions(Tenant, new UserSecurityProvider(userid), Constants.Action_EditUser);
if (!CoreContext.UserManager.UserExists(Tenant.TenantId, userid)) return null;
var user = CoreContext.UserManager.GetUsers(Tenant.TenantId, userid);
if (!CoreContext.UserManager.UserExists(user)) return null;
if (CoreContext.UserManager.IsSystemUser(user.ID))
throw new SecurityException();

View File

@ -45,7 +45,7 @@ namespace ASC.Web.Api.Controllers
userName,
Hasher.Base64Hash(password, HashAlg.SHA256));
if (user == null || !CoreContext.UserManager.UserExists(tenantId, user.ID))
if (user == null || !CoreContext.UserManager.UserExists(user))
{
throw new Exception("user not found");
}

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-components",
"version": "1.0.23",
"version": "1.0.25",
"description": "Ascensio System SIA component library",
"license": "AGPL-3.0",
"main": "dist/asc-web-components.cjs.js",

View File

@ -273,9 +273,12 @@ class FilterInput extends React.Component {
if (this.isResizeUpdate) {
this.isResizeUpdate = false;
}
const fullWidth = this.searchWrapper.current.getBoundingClientRect().width;
const filterWidth = this.filterWrapper.current.getBoundingClientRect().width;
if (fullWidth <= this.minWidth || filterWidth > fullWidth / 2) this.updateFilter();
if(this.searchWrapper.current && this.filterWrapper.current){
const fullWidth = this.searchWrapper.current.getBoundingClientRect().width;
const filterWidth = this.filterWrapper.current.getBoundingClientRect().width;
if (fullWidth <= this.minWidth || filterWidth > fullWidth / 2) this.updateFilter();
}
}
onClickFilterItem(event, filterItem) {
const currentFilterItems = cloneObjectsArray(this.state.filterValues);
@ -365,6 +368,7 @@ class FilterInput extends React.Component {
componentDidMount() {
window.addEventListener('resize', this.throttledResize);
if(this.state.filterValues.length > 0) this.updateFilter();
}
componentWillUnmount() {
window.removeEventListener('resize', this.throttledResize);

View File

@ -68,7 +68,8 @@ const TreeMenu = props => {
//console.log("TreeMenu render");
const { defaultExpandAll, defaultExpandParent, showIcon, showLine, multiple, disabled, draggable, checkable, children, switcherIcon, icon,
onDragStart, onDrop, onSelect, onDragEnter, onDragEnd, onDragLeave, onDragOver, onCheck, onExpand, onLoad, onMouseEnter, onMouseLeave, onRightClick,
defaultSelectedKeys, defaultExpandedKeys, defaultCheckedKeys} = props;
defaultSelectedKeys, defaultExpandedKeys, defaultCheckedKeys, selectedKeys} = props;
return (
<StyledTreeMenu
checkable = {!!checkable}
@ -81,6 +82,7 @@ const TreeMenu = props => {
defaultExpandParent = {!!defaultExpandParent}
icon = {icon}
selectedKeys={selectedKeys}
defaultSelectedKeys={defaultSelectedKeys}
defaultExpandedKeys={defaultExpandedKeys}
defaultCheckedKeys={defaultCheckedKeys}

View File

@ -100,7 +100,7 @@ namespace ASC.Core.Users
var sb = new StringBuilder();
//check for removed users
if (userInfo == null || !CoreContext.UserManager.UserExists(tenant.TenantId, userInfo.ID))
if (userInfo == null || !CoreContext.UserManager.UserExists(userInfo))
{
sb.Append("<span class='userLink text-medium-describe' style='white-space:nowrap;'>profile removed</span>");
}
@ -108,7 +108,7 @@ namespace ASC.Core.Users
{
var popupID = Guid.NewGuid();
sb.AppendFormat("<span class=\"userLink\" style='white-space:nowrap;' id='{0}' data-uid='{1}'>", popupID, userInfo.ID);
sb.AppendFormat("<a class='linkDescribe' href=\"{0}\">{1}</a>", userInfo.GetUserProfilePageURLGeneral(tenant.TenantId), userInfo.DisplayUserName());
sb.AppendFormat("<a class='linkDescribe' href=\"{0}\">{1}</a>", userInfo.GetUserProfilePageURLGeneral(), userInfo.DisplayUserName());
sb.Append("</span>");
sb.AppendFormat("<script language='javascript'> StudioUserProfileInfo.RegistryElement('{0}','\"{1}\"); </script>", popupID, userInfo.ID);
@ -121,9 +121,9 @@ namespace ASC.Core.Users
/// </summary>
/// <param name="userInfo"></param>
/// <returns></returns>
private static string GetUserProfilePageURLGeneral(this UserInfo userInfo, int tenantId)
private static string GetUserProfilePageURLGeneral(this UserInfo userInfo)
{
return CommonLinkUtility.GetUserProfile(tenantId, userInfo.ID);
return CommonLinkUtility.GetUserProfile(userInfo);
}
}
}

View File

@ -236,9 +236,10 @@ namespace ASC.Web.Studio.Core.Notify
if (SecurityContext.IsAuthenticated)
{
aid = SecurityContext.CurrentAccount.ID;
if (CoreContext.UserManager.UserExists(tenant.TenantId, aid))
var user = CoreContext.UserManager.GetUsers(tenant.TenantId, aid);
if (CoreContext.UserManager.UserExists(user))
{
aname = CoreContext.UserManager.GetUsers(tenant.TenantId, aid).DisplayUserName(false)
aname = user.DisplayUserName(false)
.Replace(">", "&#62")
.Replace("<", "&#60");
}

View File

@ -286,7 +286,7 @@ namespace ASC.Web.Studio.Core.Notify
public void UserInfoAddedAfterInvite(int tenantId, UserInfo newUserInfo)
{
if (!CoreContext.UserManager.UserExists(tenantId, newUserInfo.ID)) return;
if (!CoreContext.UserManager.UserExists(newUserInfo)) return;
INotifyAction notifyAction;
var footer = "social";
@ -337,9 +337,9 @@ namespace ASC.Web.Studio.Core.Notify
new TagValue(CommonTags.Analytics, analytics));
}
public void GuestInfoAddedAfterInvite(int tenantId, UserInfo newUserInfo)
public void GuestInfoAddedAfterInvite(UserInfo newUserInfo)
{
if (!CoreContext.UserManager.UserExists(tenantId, newUserInfo.ID)) return;
if (!CoreContext.UserManager.UserExists(newUserInfo)) return;
INotifyAction notifyAction;
var analytics = string.Empty;
@ -471,9 +471,9 @@ namespace ASC.Web.Studio.Core.Notify
new[] { EMailSenderName },
new TagValue(Tags.UserName, DisplayUserSettings.GetFullUserName(tenantId, recipientId)),
new TagValue(Tags.FromUserName, fromUser.DisplayUserName()),
new TagValue(Tags.FromUserLink, GetUserProfileLink(tenantId, fromUser.ID)),
new TagValue(Tags.FromUserLink, GetUserProfileLink(fromUser)),
new TagValue(Tags.ToUserName, toUser.DisplayUserName()),
new TagValue(Tags.ToUserLink, GetUserProfileLink(tenantId, toUser.ID)));
new TagValue(Tags.ToUserLink, GetUserProfileLink(toUser)));
}
public void SendMsgReassignsFailed(int tenantId, Guid recipientId, UserInfo fromUser, UserInfo toUser, string message)
@ -484,13 +484,13 @@ namespace ASC.Web.Studio.Core.Notify
new[] { EMailSenderName },
new TagValue(Tags.UserName, DisplayUserSettings.GetFullUserName(tenantId, recipientId)),
new TagValue(Tags.FromUserName, fromUser.DisplayUserName()),
new TagValue(Tags.FromUserLink, GetUserProfileLink(tenantId, fromUser.ID)),
new TagValue(Tags.FromUserLink, GetUserProfileLink(fromUser)),
new TagValue(Tags.ToUserName, toUser.DisplayUserName()),
new TagValue(Tags.ToUserLink, GetUserProfileLink(tenantId, toUser.ID)),
new TagValue(Tags.ToUserLink, GetUserProfileLink(toUser)),
new TagValue(Tags.Message, message));
}
public void SendMsgRemoveUserDataCompleted(int tenantId, Guid recipientId, Guid fromUserId, string fromUserName, long docsSpace, long crmSpace, long mailSpace, long talkSpace)
public void SendMsgRemoveUserDataCompleted(int tenantId, Guid recipientId, UserInfo user, string fromUserName, long docsSpace, long crmSpace, long mailSpace, long talkSpace)
{
client.SendNoticeToAsync(
CoreContext.Configuration.CustomMode ? Actions.RemoveUserDataCompletedCustomMode : Actions.RemoveUserDataCompleted,
@ -498,14 +498,14 @@ namespace ASC.Web.Studio.Core.Notify
new[] { EMailSenderName },
new TagValue(Tags.UserName, DisplayUserSettings.GetFullUserName(tenantId, recipientId)),
new TagValue(Tags.FromUserName, fromUserName.HtmlEncode()),
new TagValue(Tags.FromUserLink, GetUserProfileLink(tenantId, fromUserId)),
new TagValue(Tags.FromUserLink, GetUserProfileLink(user)),
new TagValue("DocsSpace", FileSizeComment.FilesSizeToString(docsSpace)),
new TagValue("CrmSpace", FileSizeComment.FilesSizeToString(crmSpace)),
new TagValue("MailSpace", FileSizeComment.FilesSizeToString(mailSpace)),
new TagValue("TalkSpace", FileSizeComment.FilesSizeToString(talkSpace)));
}
public void SendMsgRemoveUserDataFailed(int tenantId, Guid recipientId, Guid fromUserId, string fromUserName, string message)
public void SendMsgRemoveUserDataFailed(int tenantId, Guid recipientId, UserInfo user, string fromUserName, string message)
{
client.SendNoticeToAsync(
Actions.RemoveUserDataFailed,
@ -513,13 +513,13 @@ namespace ASC.Web.Studio.Core.Notify
new[] { EMailSenderName },
new TagValue(Tags.UserName, DisplayUserSettings.GetFullUserName(tenantId, recipientId)),
new TagValue(Tags.FromUserName, fromUserName.HtmlEncode()),
new TagValue(Tags.FromUserLink, GetUserProfileLink(tenantId, fromUserId)),
new TagValue(Tags.FromUserLink, GetUserProfileLink(user)),
new TagValue(Tags.Message, message));
}
public void SendAdminWelcome(UserInfo newUserInfo, int tenantId)
{
if (!CoreContext.UserManager.UserExists(tenantId, newUserInfo.ID)) return;
if (!CoreContext.UserManager.UserExists(newUserInfo)) return;
if (!newUserInfo.IsActive)
throw new ArgumentException("User is not activated yet!");
@ -741,7 +741,7 @@ namespace ASC.Web.Studio.Core.Notify
public void SendInvitePersonal(int tenantId, string email, string additionalMember = "", bool analytics = true)
{
var newUserInfo = CoreContext.UserManager.GetUserByEmail(tenantId, email);
if (CoreContext.UserManager.UserExists(tenantId, newUserInfo.ID)) return;
if (CoreContext.UserManager.UserExists(newUserInfo)) return;
var lang = CoreContext.Configuration.CustomMode
? "ru-RU"
@ -851,9 +851,9 @@ namespace ASC.Web.Studio.Core.Notify
return CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetMyStaff());
}
private static string GetUserProfileLink(int tenantId, Guid userId)
private static string GetUserProfileLink(UserInfo userInfo)
{
return CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetUserProfile(tenantId, userId));
return CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetUserProfile(userInfo));
}
private static string AddHttpToUrl(string url)

View File

@ -118,7 +118,7 @@ namespace ASC.Web.Studio.Core.Notify
{
Date = f.CreatedDate,
UserName = f.Author != null && f.Author.UserInfo != null ? f.Author.UserInfo.DisplayUserName() : string.Empty,
UserAbsoluteURL = f.Author != null && f.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(f.Author.UserInfo.GetUserProfilePageURL(tenant.TenantId)) : string.Empty,
UserAbsoluteURL = f.Author != null && f.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(f.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
Title = HtmlUtil.GetText(f.Title, 512),
URL = CommonLinkUtility.GetFullAbsolutePath(f.ItemUrl),
BreadCrumbs = new string[0],
@ -141,7 +141,7 @@ namespace ASC.Web.Studio.Core.Notify
{
Date = prawbc.CreatedDate,
UserName = prawbc.Author != null && prawbc.Author.UserInfo != null ? prawbc.Author.UserInfo.DisplayUserName() : string.Empty,
UserAbsoluteURL = prawbc.Author != null && prawbc.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(prawbc.Author.UserInfo.GetUserProfilePageURL(tenant.TenantId)) : string.Empty,
UserAbsoluteURL = prawbc.Author != null && prawbc.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(prawbc.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
Title = HtmlUtil.GetText(prawbc.Title, 512),
URL = CommonLinkUtility.GetFullAbsolutePath(prawbc.ItemUrl),
BreadCrumbs = new string[0],
@ -161,7 +161,7 @@ namespace ASC.Web.Studio.Core.Notify
{
Date = ls.CreatedDate,
UserName = ls.Author != null && ls.Author.UserInfo != null ? ls.Author.UserInfo.DisplayUserName() : string.Empty,
UserAbsoluteURL = ls.Author != null && ls.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(ls.Author.UserInfo.GetUserProfilePageURL(tenant.TenantId)) : string.Empty,
UserAbsoluteURL = ls.Author != null && ls.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(ls.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
Title = HtmlUtil.GetText(ls.Title, 512),
URL = CommonLinkUtility.GetFullAbsolutePath(ls.ItemUrl),
BreadCrumbs = i == 0 ? new string[1] { gr.Key } : new string[0],
@ -175,7 +175,7 @@ namespace ASC.Web.Studio.Core.Notify
activities.Add(ProjectsProductName, whatsNewUserActivityGroupByPrjs);
}
if (0 < activities.Count)
if (activities.Count > 0)
{
log.InfoFormat("Send whats new to {0}", user.Email);
client.SendNoticeAsync(

View File

@ -69,7 +69,7 @@ namespace ASC.Web.Core.Users
{
return string.Empty;
}
if (!userInfo.ID.Equals(Guid.Empty) && !CoreContext.UserManager.UserExists(userInfo.Tenant, userInfo.ID))
if (!userInfo.ID.Equals(Guid.Empty) && !CoreContext.UserManager.UserExists(userInfo))
{
return "profile removed";
}

View File

@ -37,16 +37,16 @@ namespace ASC.Core.Users
{
public static class StudioUserInfoExtension
{
public static string GetUserProfilePageURL(this UserInfo userInfo, int tenantId)
public static string GetUserProfilePageURL(this UserInfo userInfo)
{
return userInfo == null ? "" : CommonLinkUtility.GetUserProfile(tenantId, userInfo.ID);
return userInfo == null ? "" : CommonLinkUtility.GetUserProfile(userInfo);
}
public static string RenderProfileLink(this UserInfo userInfo, Guid productID, int tenantId)
{
var sb = new StringBuilder();
if (userInfo == null || !CoreContext.UserManager.UserExists(tenantId, userInfo.ID))
if (userInfo == null || !CoreContext.UserManager.UserExists(userInfo))
{
sb.Append("<span class='userLink text-medium-describe'>");
sb.Append(Resource.ProfileRemoved);
@ -61,7 +61,7 @@ namespace ASC.Core.Users
else
{
sb.AppendFormat("<span class=\"userLink\" id=\"{0}\" data-uid=\"{1}\" data-pid=\"{2}\">", Guid.NewGuid(), userInfo.ID, productID);
sb.AppendFormat("<a class='linkDescribe' href=\"{0}\">{1}</a>", userInfo.GetUserProfilePageURL(tenantId), userInfo.DisplayUserName());
sb.AppendFormat("<a class='linkDescribe' href=\"{0}\">{1}</a>", userInfo.GetUserProfilePageURL(), userInfo.DisplayUserName());
sb.Append("</span>");
}
return sb.ToString();
@ -73,7 +73,7 @@ namespace ASC.Core.Users
var linkCss = string.IsNullOrEmpty(linkCssClass) ? "" : linkCssClass;
var sb = new StringBuilder();
if (userInfo == null || !CoreContext.UserManager.UserExists(tenantId, userInfo.ID))
if (userInfo == null || !CoreContext.UserManager.UserExists(userInfo))
{
sb.AppendFormat("<span class='{0}'>", containerCss);
sb.Append(Resource.ProfileRemoved);
@ -88,7 +88,7 @@ namespace ASC.Core.Users
else
{
sb.AppendFormat("<span class=\"{0}\" id=\"{1}\" data-uid=\"{2}\" >", containerCss, Guid.NewGuid(), userInfo.ID);
sb.AppendFormat("<a class='{0}' href=\"{1}\">{2}</a>", linkCss, userInfo.GetUserProfilePageURL(tenantId), userInfo.DisplayUserName());
sb.AppendFormat("<a class='{0}' href=\"{1}\">{2}</a>", linkCss, userInfo.GetUserProfilePageURL(), userInfo.DisplayUserName());
sb.Append("</span>");
}
return sb.ToString();

View File

@ -122,7 +122,7 @@ namespace ASC.Web.Core.Users
{
if (isVisitor)
{
StudioNotifyService.GuestInfoAddedAfterInvite(tenant.TenantId, newUserInfo);
StudioNotifyService.GuestInfoAddedAfterInvite(newUserInfo);
}
else
{
@ -183,7 +183,7 @@ namespace ASC.Web.Core.Users
}
var userInfo = CoreContext.UserManager.GetUserByEmail(tenantId, email);
if (!CoreContext.UserManager.UserExists(tenantId, userInfo.ID) || string.IsNullOrEmpty(userInfo.Email))
if (!CoreContext.UserManager.UserExists(userInfo) || string.IsNullOrEmpty(userInfo.Email))
{
throw new Exception(string.Format(Resource.ErrorUserNotFoundByEmail, email));
}

View File

@ -162,15 +162,6 @@ namespace ASC.Web.Studio.Utility
#region user profile link
public static string GetUserProfile()
{
return GetUserProfile(CoreContext.TenantManager.GetCurrentTenant().TenantId);
}
public static string GetUserProfile(int tenantId)
{
return GetUserProfile(tenantId, null);
}
public static string GetUserProfile(int tenantId, Guid userID)
{
if (!CoreContext.UserManager.UserExists(tenantId, userID))
@ -179,6 +170,14 @@ namespace ASC.Web.Studio.Utility
return GetUserProfile(tenantId, userID.ToString());
}
public static string GetUserProfile(UserInfo user)
{
if (!CoreContext.UserManager.UserExists(user))
return GetEmployees();
return GetUserProfile(user, true);
}
public static string GetUserProfile(int tenantId, string user, bool absolute = true)
{
var queryParams = "";
@ -206,6 +205,17 @@ namespace ASC.Web.Studio.Utility
return url;
}
public static string GetUserProfile(UserInfo user, bool absolute = true)
{
var queryParams = user.ID != Guid.Empty ? GetUserParamsPair(user) : ParamName_UserUserName + "=" + HttpUtility.UrlEncode(user.UserName);
var url = absolute ? ToAbsolute("~/products/people/") : "/products/people/";
url += "profile.aspx?";
url += queryParams;
return url;
}
public static string GetUserProfile(int tenantId, Guid user, bool absolute = true)
{
var queryParams = GetUserParamsPair(tenantId, user);
@ -449,15 +459,12 @@ namespace ASC.Web.Studio.Utility
public static string GetUserParamsPair(int tenantId, Guid userID)
{
return
CoreContext.UserManager.UserExists(tenantId, userID)
? GetUserParamsPair(CoreContext.UserManager.GetUsers(tenantId, userID))
: "";
return GetUserParamsPair(CoreContext.UserManager.GetUsers(tenantId, userID));
}
public static string GetUserParamsPair(UserInfo user)
{
if (user == null || string.IsNullOrEmpty(user.UserName))
if (user == null || string.IsNullOrEmpty(user.UserName) || !CoreContext.UserManager.UserExists(user))
return "";
return string.Format("{0}={1}", ParamName_UserUserName, HttpUtility.UrlEncode(user.UserName.ToLowerInvariant()));

View File

@ -33,6 +33,8 @@ namespace ASC.Web.Core.Utility.Skins
{
public static class WebImageSupplier
{
private static string FolderName { get; } = ConfigurationManager.AppSettings["web:images"];
public static string GetAbsoluteWebPath(string imgFileName)
{
return GetAbsoluteWebPath(imgFileName, Guid.Empty);
@ -68,7 +70,7 @@ namespace ASC.Web.Core.Utility.Skins
private static string GetPartImageFolderRel(Guid partID)
{
var folderName = ConfigurationManager.AppSettings["web:images"];
var folderName = FolderName;
string itemFolder = null;
if (!Guid.Empty.Equals(partID))
{

View File

@ -39,7 +39,10 @@ class FilterStory extends React.Component {
super(props);
this.state = {
selectedFilterData: {
inputValue: "text"
inputValue: "text",
filterValues: [
{key: "1", group: "filter-status"}
]
}
};
this.buttonClick = this.buttonClick.bind(this);