mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
237 lines (201 loc) • 8.73 kB
text/typescript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {General, Preferences} from '../constants';
import {localizeMessage} from 'utils/i18n_utils';
import {ChannelMembership} from 'types/channels';
import {TeamMembership} from 'types/teams';
import {UserProfile} from 'types/users';
import {IDMappedObjects, $ID, Dictionary} from 'types/utilities';
export function getFullName(user: UserProfile): string {
if (user.first_name && user.last_name) {
return user.first_name + ' ' + user.last_name;
} else if (user.first_name) {
return user.first_name;
} else if (user.last_name) {
return user.last_name;
}
return '';
}
export function displayUsername(
user: UserProfile,
teammateNameDisplay: string,
useFallbackUsername = true,
): string {
let name = useFallbackUsername ? localizeMessage('channel_loader.someone', 'Someone') : '';
if (user) {
if (teammateNameDisplay === Preferences.DISPLAY_PREFER_NICKNAME) {
name = user.nickname || getFullName(user);
} else if (teammateNameDisplay === Preferences.DISPLAY_PREFER_FULL_NAME) {
name = getFullName(user);
} else {
name = user.username;
}
if (!name || name.trim().length === 0) {
name = user.username;
}
}
return name;
}
export function spaceSeparatedStringIncludes(spaceSeparated: string, item: string): boolean {
const items = spaceSeparated.split(' ');
return items.includes(item);
}
export function isAdmin(roles: string): boolean {
return isSystemAdmin(roles) || isTeamAdmin(roles);
}
export function isGuest(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, 'system_guest');
}
export function isTeamAdmin(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.TEAM_ADMIN_ROLE);
}
export function isSystemAdmin(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.SYSTEM_ADMIN_ROLE);
}
export function includesAnAdminRole(roles: string): boolean {
const rolesArray = roles.split(' ');
return [
General.SYSTEM_ADMIN_ROLE,
General.SYSTEM_USER_MANAGER_ROLE,
General.SYSTEM_READ_ONLY_ADMIN_ROLE,
General.SYSTEM_MANAGER_ROLE,
].some((el) => rolesArray.includes(el));
}
export function isChannelAdmin(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.CHANNEL_ADMIN_ROLE);
}
export function hasUserAccessTokenRole(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.SYSTEM_USER_ACCESS_TOKEN_ROLE);
}
export function hasPostAllRole(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.SYSTEM_POST_ALL_ROLE);
}
export function hasPostAllPublicRole(roles: string): boolean {
return spaceSeparatedStringIncludes(roles, General.SYSTEM_POST_ALL_PUBLIC_ROLE);
}
export function profileListToMap(profileList: UserProfile[]): IDMappedObjects<UserProfile> {
const profiles: Dictionary<UserProfile> = {};
for (let i = 0; i < profileList.length; i++) {
profiles[profileList[i].id] = profileList[i];
}
return profiles;
}
export function removeUserFromList(userId: $ID<UserProfile>, list: UserProfile[]): UserProfile[] {
for (let i = list.length - 1; i >= 0; i--) {
if (list[i].id === userId) {
list.splice(i, 1);
return list;
}
}
return list;
}
// Splits the term by a splitStr and composes a list of the parts of
// the split concatenated with the rest, forming a set of suggesitons
// matchable with startsWith
//
// E.g.: for "one.two.three" by "." it would yield
// ["one.two.three", ".two.three", "two.three", ".three", "three"]
export function getSuggestionsSplitBy(term: string, splitStr: string): string[] {
const splitTerm = term.split(splitStr);
const initialSuggestions = splitTerm.map((st, i) => splitTerm.slice(i).join(splitStr));
let suggestions: string[] = [];
if (splitStr === ' ') {
suggestions = initialSuggestions;
} else {
suggestions = initialSuggestions.reduce((acc, val) => {
if (acc.length === 0) {
acc.push(val);
} else {
acc.push(splitStr + val, val);
}
return acc;
}, [] as string[]);
}
return suggestions;
}
export function getSuggestionsSplitByMultiple(term: string, splitStrs: string[]): string[] {
const suggestions = splitStrs.reduce((acc, val) => {
getSuggestionsSplitBy(term, val).forEach((suggestion) => acc.add(suggestion));
return acc;
}, new Set<string>());
return [...suggestions];
}
export function nameSuggestionsForUser(user: UserProfile): string[] {
const profileSuggestions: string[] = [];
const usernameSuggestions = getSuggestionsSplitByMultiple((user.username || '').toLowerCase(), General.AUTOCOMPLETE_SPLIT_CHARACTERS);
profileSuggestions.push(...usernameSuggestions);
const first = (user.first_name || '').toLowerCase();
const last = (user.last_name || '').toLowerCase();
const full = first + ' ' + last;
profileSuggestions.push(first, last, full);
profileSuggestions.push((user.nickname || '').toLowerCase());
profileSuggestions.push((user.position || '').toLowerCase());
const email = (user.email || '').toLowerCase();
profileSuggestions.push(email);
const split = email.split('@');
if (split.length > 1) {
profileSuggestions.push(split[1]);
}
return profileSuggestions;
}
export function filterProfilesStartingWithTerm(users: UserProfile[], term: string): UserProfile[] {
const lowercasedTerm = term.toLowerCase();
let trimmedTerm = lowercasedTerm;
if (trimmedTerm.startsWith('@')) {
trimmedTerm = trimmedTerm.substr(1);
}
return users.filter((user: UserProfile) => {
if (!user) {
return false;
}
const profileSuggestions = nameSuggestionsForUser(user);
return profileSuggestions.filter((suggestion) => suggestion !== '').some((suggestion) => suggestion.startsWith(trimmedTerm));
});
}
export function filterProfilesMatchingWithTerm(users: UserProfile[], term: string): UserProfile[] {
const lowercasedTerm = term.toLowerCase();
let trimmedTerm = lowercasedTerm;
if (trimmedTerm.startsWith('@')) {
trimmedTerm = trimmedTerm.substr(1);
}
return users.filter((user: UserProfile) => {
if (!user) {
return false;
}
const profileSuggestions = nameSuggestionsForUser(user);
return profileSuggestions.filter((suggestion) => suggestion !== '').some((suggestion) => suggestion.includes(trimmedTerm));
});
}
export function sortByUsername(a: UserProfile, b: UserProfile): number {
const nameA = a.username;
const nameB = b.username;
return nameA.localeCompare(nameB);
}
function checkUserHasRole(user: UserProfile, userIsNotAdminOrGuest: boolean, membership: TeamMembership | ChannelMembership | undefined, role: string) {
const isSystemRole = role.includes('system');
return (
(
// If role is system user then user cannot have system admin or system guest roles
isSystemRole && user.roles.includes(role) && (
(role === General.SYSTEM_USER_ROLE && userIsNotAdminOrGuest) ||
role !== General.SYSTEM_USER_ROLE
)
) || (
// If user is a system admin or a system guest then ignore team and channel memberships
!isSystemRole && userIsNotAdminOrGuest && (
(role === General.TEAM_ADMIN_ROLE && membership?.scheme_admin) ||
(role === General.CHANNEL_ADMIN_ROLE && membership?.scheme_admin) ||
(role === General.TEAM_USER_ROLE && membership?.scheme_user && !membership?.scheme_admin) ||
(role === General.CHANNEL_USER_ROLE && membership?.scheme_user && !membership?.scheme_admin)
)
)
);
}
export function applyRolesFilters(user: UserProfile, filterRoles: string[], excludeRoles: string[], membership: TeamMembership | ChannelMembership | undefined): boolean {
const userIsNotAdminOrGuest = !(user.roles.includes(General.SYSTEM_ADMIN_ROLE) || user.roles.includes(General.SYSTEM_GUEST_ROLE));
const userHasExcludedRole = excludeRoles.some(checkUserHasRole.bind(this, user, userIsNotAdminOrGuest, membership));
if (userHasExcludedRole) {
return false;
}
return filterRoles.length === 0 || filterRoles.some(checkUserHasRole.bind(this, user, userIsNotAdminOrGuest, membership));
}