[MM-53904] Fix MM-53904 (#24622)
* Fix MM-53904 * Simplify regex * Simplify utils regex * Fix lint * Address feedback and polish regex --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
6f4d362f9f
Коммит
f62634622f
@@ -11,6 +11,8 @@ import PlaybookRunner from 'components/channel_layout/playbook_runner';
|
|||||||
import LoadingScreen from 'components/loading_screen';
|
import LoadingScreen from 'components/loading_screen';
|
||||||
import PermalinkView from 'components/permalink_view';
|
import PermalinkView from 'components/permalink_view';
|
||||||
|
|
||||||
|
import {IDENTIFIER_PATH_PATTERN, ID_PATH_PATTERN, TEAM_NAME_PATH_PATTERN} from 'utils/path';
|
||||||
|
|
||||||
import type {OwnProps, PropsFromRedux} from './index';
|
import type {OwnProps, PropsFromRedux} from './index';
|
||||||
|
|
||||||
const LazyChannelHeaderMobile = makeAsyncComponent(
|
const LazyChannelHeaderMobile = makeAsyncComponent(
|
||||||
@@ -92,7 +94,7 @@ export default class CenterChannel extends React.PureComponent<Props, State> {
|
|||||||
<div className='row main'>
|
<div className='row main'>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path={`${url}/pl/:postid`}
|
path={`${url}/pl/:postid(${ID_PATH_PATTERN})`}
|
||||||
render={(props) => (
|
render={(props) => (
|
||||||
<PermalinkView
|
<PermalinkView
|
||||||
{...props}
|
{...props}
|
||||||
@@ -101,22 +103,22 @@ export default class CenterChannel extends React.PureComponent<Props, State> {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path='/:team/:path(channels|messages)/:identifier/:postid?'
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/:path(channels|messages)/:identifier(${IDENTIFIER_PATH_PATTERN})/:postid(${ID_PATH_PATTERN})?`}
|
||||||
component={ChannelIdentifierRouter}
|
component={ChannelIdentifierRouter}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path='/:team/_playbooks/:playbookId/run'
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/_playbooks/:playbookId(${ID_PATH_PATTERN})/run`}
|
||||||
>
|
>
|
||||||
<PlaybookRunner/>
|
<PlaybookRunner/>
|
||||||
</Route>
|
</Route>
|
||||||
{isCollapsedThreadsEnabled ? (
|
{isCollapsedThreadsEnabled ? (
|
||||||
<Route
|
<Route
|
||||||
path='/:team/threads/:threadIdentifier?'
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/threads/:threadIdentifier(${ID_PATH_PATTERN})?`}
|
||||||
component={LazyGlobalThreads}
|
component={LazyGlobalThreads}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Route
|
<Route
|
||||||
path='/:team/drafts'
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/drafts`}
|
||||||
component={LazyDrafts}
|
component={LazyDrafts}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ exports[`components/Root Routes Should mount public product routes 1`] = `
|
|||||||
/>
|
/>
|
||||||
<LoggedInRoute
|
<LoggedInRoute
|
||||||
component={[Function]}
|
component={[Function]}
|
||||||
path="/:team"
|
path="/:team([a-z0-9\\\\-_]+)"
|
||||||
theme={Object {}}
|
theme={Object {}}
|
||||||
/>
|
/>
|
||||||
<Connect(RootRedirect) />
|
<Connect(RootRedirect) />
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import Pluggable from 'plugins/pluggable';
|
|||||||
import A11yController from 'utils/a11y_controller';
|
import A11yController from 'utils/a11y_controller';
|
||||||
import {PageLoadContext, StoragePrefixes} from 'utils/constants';
|
import {PageLoadContext, StoragePrefixes} from 'utils/constants';
|
||||||
import {EmojiIndicesByAlias} from 'utils/emoji';
|
import {EmojiIndicesByAlias} from 'utils/emoji';
|
||||||
|
import {TEAM_NAME_PATH_PATTERN} from 'utils/path';
|
||||||
import {getSiteURL} from 'utils/url';
|
import {getSiteURL} from 'utils/url';
|
||||||
import * as UserAgent from 'utils/user_agent';
|
import * as UserAgent from 'utils/user_agent';
|
||||||
import * as Utils from 'utils/utils';
|
import * as Utils from 'utils/utils';
|
||||||
@@ -111,7 +112,7 @@ const OnBoardingTaskList = makeAsyncComponent('OnboardingTaskList', LazyOnBoardi
|
|||||||
|
|
||||||
type LoggedInRouteProps<T> = {
|
type LoggedInRouteProps<T> = {
|
||||||
component: React.ComponentType<T>;
|
component: React.ComponentType<T>;
|
||||||
path: string;
|
path: string | string[];
|
||||||
theme?: Theme; // the routes that send the theme are the ones that will actually need to show the onboarding tasklist
|
theme?: Theme; // the routes that send the theme are the ones that will actually need to show the onboarding tasklist
|
||||||
};
|
};
|
||||||
function LoggedInRoute<T>(props: LoggedInRouteProps<T>) {
|
function LoggedInRoute<T>(props: LoggedInRouteProps<T>) {
|
||||||
@@ -644,7 +645,7 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
))}
|
))}
|
||||||
<LoggedInRoute
|
<LoggedInRoute
|
||||||
theme={this.props.theme}
|
theme={this.props.theme}
|
||||||
path={'/:team'}
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})`}
|
||||||
component={TeamController}
|
component={TeamController}
|
||||||
/>
|
/>
|
||||||
<RootRedirect/>
|
<RootRedirect/>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import useTelemetryIdentitySync from 'components/common/hooks/useTelemetryIdenti
|
|||||||
|
|
||||||
import Constants from 'utils/constants';
|
import Constants from 'utils/constants';
|
||||||
import {cmdOrCtrlPressed, isKeyPressed} from 'utils/keyboard';
|
import {cmdOrCtrlPressed, isKeyPressed} from 'utils/keyboard';
|
||||||
|
import {TEAM_NAME_PATH_PATTERN} from 'utils/path';
|
||||||
import {isIosSafari} from 'utils/user_agent';
|
import {isIosSafari} from 'utils/user_agent';
|
||||||
|
|
||||||
import type {OwnProps, PropsFromRedux} from './index';
|
import type {OwnProps, PropsFromRedux} from './index';
|
||||||
@@ -208,17 +209,17 @@ function TeamController(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path={'/:team/integrations'}
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/integrations`}
|
||||||
component={BackstageController}
|
component={BackstageController}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={'/:team/emoji'}
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/emoji`}
|
||||||
component={BackstageController}
|
component={BackstageController}
|
||||||
/>
|
/>
|
||||||
{props.plugins?.map((plugin) => (
|
{props.plugins?.map((plugin) => (
|
||||||
<Route
|
<Route
|
||||||
key={plugin.id}
|
key={plugin.id}
|
||||||
path={'/:team/' + (plugin as any).route}
|
path={`/:team(${TEAM_NAME_PATH_PATTERN})/` + (plugin as any).route}
|
||||||
render={() => (
|
render={() => (
|
||||||
<Pluggable
|
<Pluggable
|
||||||
pluggableName={'NeedsTeamComponent'}
|
pluggableName={'NeedsTeamComponent'}
|
||||||
|
|||||||
19
webapp/channels/src/utils/path.ts
Обычный файл
19
webapp/channels/src/utils/path.ts
Обычный файл
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
export const ID_PATH_PATTERN = '[a-z0-9]{26}';
|
||||||
|
|
||||||
|
// This should cover:
|
||||||
|
// - Team name (lowercase english characters, numbers or -)
|
||||||
|
// - Two ids separated by __ (userID__userID)
|
||||||
|
export const TEAM_NAME_PATH_PATTERN = '[a-z0-9\\-_]+';
|
||||||
|
|
||||||
|
// This should cover:
|
||||||
|
// - Channel name
|
||||||
|
// - Channel ID
|
||||||
|
// - Group Channel Name (40 length UID)
|
||||||
|
// - DM Name (userID__userID)
|
||||||
|
// - Username prefixed by a @
|
||||||
|
// - User ID
|
||||||
|
// - Email
|
||||||
|
export const IDENTIFIER_PATH_PATTERN = '[@a-zA-Z\\-_0-9][@a-zA-Z\\-_0-9.]*';
|
||||||
@@ -1333,7 +1333,7 @@ export function isValidPassword(password: string, passwordConfig: ReturnType<typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isChannelOrPermalink(link: string) {
|
function isChannelOrPermalink(link: string) {
|
||||||
let match = (/\/([^/]+)\/channels\/(\S+)/).exec(link);
|
let match = (/\/([a-z0-9\-_]+)\/channels\/([a-z0-9\-__][a-z0-9\-__.]+)/).exec(link);
|
||||||
if (match) {
|
if (match) {
|
||||||
return {
|
return {
|
||||||
type: 'channel',
|
type: 'channel',
|
||||||
@@ -1341,7 +1341,7 @@ function isChannelOrPermalink(link: string) {
|
|||||||
channelName: match[2],
|
channelName: match[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
match = (/\/([^/]+)\/pl\/(\w+)/).exec(link);
|
match = (/\/([a-z0-9\-__]+)\/pl\/([a-z0-9]+)/).exec(link);
|
||||||
if (match) {
|
if (match) {
|
||||||
return {
|
return {
|
||||||
type: 'permalink',
|
type: 'permalink',
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user