Merge branch 'release-3.5'
Этот коммит содержится в:
@@ -376,7 +376,7 @@ func sendWelcomeEmail(c *Context, userId string, email string, siteURL string, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !verified {
|
if !verified {
|
||||||
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId), url.QueryEscape(email))
|
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId+utils.Cfg.EmailSettings.InviteSalt), url.QueryEscape(email))
|
||||||
bodyPage.Props["VerifyUrl"] = link
|
bodyPage.Props["VerifyUrl"] = link
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ func addDirectChannels(teamId string, user *model.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendVerifyEmail(c *Context, userId, userEmail, siteURL string) {
|
func SendVerifyEmail(c *Context, userId, userEmail, siteURL string) {
|
||||||
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId), url.QueryEscape(userEmail))
|
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId+utils.Cfg.EmailSettings.InviteSalt), url.QueryEscape(userEmail))
|
||||||
|
|
||||||
url, _ := url.Parse(siteURL)
|
url, _ := url.Parse(siteURL)
|
||||||
|
|
||||||
@@ -1858,7 +1858,7 @@ func sendEmailChangeEmail(c *Context, oldEmail, newEmail, siteURL string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendEmailChangeVerifyEmail(c *Context, userId, newUserEmail, siteURL string) {
|
func SendEmailChangeVerifyEmail(c *Context, userId, newUserEmail, siteURL string) {
|
||||||
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId), url.QueryEscape(newUserEmail))
|
link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId+utils.Cfg.EmailSettings.InviteSalt), url.QueryEscape(newUserEmail))
|
||||||
|
|
||||||
subject := fmt.Sprintf("[%v] %v", utils.Cfg.TeamSettings.SiteName, c.T("api.templates.email_change_verify_subject",
|
subject := fmt.Sprintf("[%v] %v", utils.Cfg.TeamSettings.SiteName, c.T("api.templates.email_change_verify_subject",
|
||||||
map[string]interface{}{"TeamDisplayName": utils.Cfg.TeamSettings.SiteName}))
|
map[string]interface{}{"TeamDisplayName": utils.Cfg.TeamSettings.SiteName}))
|
||||||
@@ -2260,7 +2260,7 @@ func verifyEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.ComparePassword(hashedId, userId) {
|
if model.ComparePassword(hashedId, userId+utils.Cfg.EmailSettings.InviteSalt) {
|
||||||
if c.Err = (<-Srv.Store.User().VerifyEmail(userId)).Err; c.Err != nil {
|
if c.Err = (<-Srv.Store.User().VerifyEmail(userId)).Err; c.Err != nil {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -50,13 +50,13 @@ export function emitChannelClickEvent(channel) {
|
|||||||
AsyncClient.updateLastViewedAt(chan.id);
|
AsyncClient.updateLastViewedAt(chan.id);
|
||||||
loadPosts(chan.id);
|
loadPosts(chan.id);
|
||||||
trackPage();
|
trackPage();
|
||||||
|
});
|
||||||
|
|
||||||
AppDispatcher.handleViewAction({
|
AppDispatcher.handleViewAction({
|
||||||
type: ActionTypes.CLICK_CHANNEL,
|
type: ActionTypes.CLICK_CHANNEL,
|
||||||
name: chan.name,
|
name: chan.name,
|
||||||
id: chan.id,
|
id: chan.id,
|
||||||
prev: ChannelStore.getCurrentId()
|
prev: ChannelStore.getCurrentId()
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,21 +461,23 @@ export function emitRemoteUserTypingEvent(channelId, userId, postParentId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function emitUserLoggedOutEvent(redirectTo) {
|
export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = true) {
|
||||||
const rURL = (redirectTo && typeof redirectTo === 'string') ? redirectTo : '/';
|
|
||||||
Client.logout(
|
Client.logout(
|
||||||
() => {
|
() => {
|
||||||
BrowserStore.signalLogout();
|
if (shouldSignalLogout) {
|
||||||
|
BrowserStore.signalLogout();
|
||||||
|
}
|
||||||
|
|
||||||
BrowserStore.clear();
|
BrowserStore.clear();
|
||||||
ErrorStore.clearLastError();
|
ErrorStore.clearLastError();
|
||||||
PreferenceStore.clear();
|
PreferenceStore.clear();
|
||||||
UserStore.clear();
|
UserStore.clear();
|
||||||
TeamStore.clear();
|
TeamStore.clear();
|
||||||
newLocalizationSelected(global.window.mm_config.DefaultClientLocale);
|
newLocalizationSelected(global.window.mm_config.DefaultClientLocale);
|
||||||
browserHistory.push(rURL);
|
browserHistory.push(redirectTo);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
browserHistory.push(rURL);
|
browserHistory.push(redirectTo);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,7 +206,12 @@ export default class Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (successCallback) {
|
if (successCallback) {
|
||||||
successCallback(res.body, res);
|
if (res.body) {
|
||||||
|
successCallback(res.body, res);
|
||||||
|
} else {
|
||||||
|
console.error('Missing response body for ' + methodName); // eslint-disable-line no-console
|
||||||
|
successCallback('', res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1952,6 +1957,11 @@ export default class Client {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return error(err);
|
return error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!res.body) {
|
||||||
|
console.error('Missing response body for samlCertificateStatus'); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
return success(res.body);
|
return success(res.body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ class WebClientClass extends Client {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return error(err);
|
return error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!res.body) {
|
||||||
|
console.error('Missing response body for getYoutubeVideoInfo'); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
return success(res.body);
|
return success(res.body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {loadEmoji} from 'actions/emoji_actions.jsx';
|
|||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
import {browserHistory} from 'react-router/es6';
|
|
||||||
|
|
||||||
const BACKSPACE_CHAR = 8;
|
const BACKSPACE_CHAR = 8;
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
@@ -41,7 +39,7 @@ export default class LoggedIn extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('detected logout from a different tab'); //eslint-disable-line no-console
|
console.log('detected logout from a different tab'); //eslint-disable-line no-console
|
||||||
browserHistory.push('/');
|
GlobalActions.emitUserLoggedOutEvent('/', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
|
if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import FileAttachmentListContainer from './file_attachment_list_container.jsx';
|
|||||||
import PendingPostOptions from 'components/post_view/components/pending_post_options.jsx';
|
import PendingPostOptions from 'components/post_view/components/pending_post_options.jsx';
|
||||||
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
||||||
import ProfilePicture from 'components/profile_picture.jsx';
|
import ProfilePicture from 'components/profile_picture.jsx';
|
||||||
|
import RhsDropdown from 'components/rhs_dropdown.jsx';
|
||||||
|
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
@@ -218,24 +219,8 @@ export default class RhsComment extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='dropdown'>
|
<RhsDropdown dropdownContents={dropdownContents}/>
|
||||||
<a
|
);
|
||||||
href='#'
|
|
||||||
className='post__dropdown dropdown-toggle'
|
|
||||||
type='button'
|
|
||||||
data-toggle='dropdown'
|
|
||||||
aria-expanded='false'
|
|
||||||
/>
|
|
||||||
<div className='dropdown-menu__content'>
|
|
||||||
<ul
|
|
||||||
className='dropdown-menu'
|
|
||||||
role='menu'
|
|
||||||
>
|
|
||||||
{dropdownContents}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
61
webapp/components/rhs_dropdown.jsx
Обычный файл
61
webapp/components/rhs_dropdown.jsx
Обычный файл
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import * as Agent from 'utils/user_agent.jsx';
|
||||||
|
import RhsDropdownMenu from 'components/rhs_dropdown_menu.jsx';
|
||||||
|
|
||||||
|
import {Dropdown} from 'react-bootstrap';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export default class RhsDropdown extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.toggleDropdown = this.toggleDropdown.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showDropdown: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDropdown(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
const showDropdown = !this.state.showDropdown;
|
||||||
|
if (Agent.isMobile() || Agent.isMobileApp()) {
|
||||||
|
const scroll = document.querySelector('.scrollbar--view');
|
||||||
|
if (showDropdown) {
|
||||||
|
scroll.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
scroll.style.overflow = 'scroll';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({showDropdown});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
open={this.state.showDropdown}
|
||||||
|
onClose={this.toggleDropdown}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
className='post__dropdown dropdown-toggle'
|
||||||
|
bsRole='toggle'
|
||||||
|
onClick={this.toggleDropdown}
|
||||||
|
/>
|
||||||
|
<RhsDropdownMenu>
|
||||||
|
{this.props.dropdownContents}
|
||||||
|
</RhsDropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RhsDropdown.propTypes = {
|
||||||
|
dropdownContents: React.PropTypes.array.isRequired
|
||||||
|
};
|
||||||
22
webapp/components/rhs_dropdown_menu.jsx
Обычный файл
22
webapp/components/rhs_dropdown_menu.jsx
Обычный файл
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import {Dropdown} from 'react-bootstrap';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export default class RhsDropdownMenu extends Dropdown.Menu {
|
||||||
|
constructor(props) { //eslint-disable-line no-useless-constructor
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className='dropdown-menu__content'
|
||||||
|
onClick={this.props.onClose}
|
||||||
|
>
|
||||||
|
{super.render()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import PostBodyAdditionalContent from 'components/post_view/components/post_body
|
|||||||
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
||||||
import FileAttachmentListContainer from './file_attachment_list_container.jsx';
|
import FileAttachmentListContainer from './file_attachment_list_container.jsx';
|
||||||
import ProfilePicture from 'components/profile_picture.jsx';
|
import ProfilePicture from 'components/profile_picture.jsx';
|
||||||
|
import RhsDropdown from 'components/rhs_dropdown.jsx';
|
||||||
|
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
@@ -228,23 +229,7 @@ export default class RhsRootPost extends React.Component {
|
|||||||
var rootOptions = '';
|
var rootOptions = '';
|
||||||
if (dropdownContents.length > 0) {
|
if (dropdownContents.length > 0) {
|
||||||
rootOptions = (
|
rootOptions = (
|
||||||
<div className='dropdown'>
|
<RhsDropdown dropdownContents={dropdownContents}/>
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
className='post__dropdown dropdown-toggle'
|
|
||||||
type='button'
|
|
||||||
data-toggle='dropdown'
|
|
||||||
aria-expanded='false'
|
|
||||||
/>
|
|
||||||
<div className='dropdown-menu__content'>
|
|
||||||
<ul
|
|
||||||
className='dropdown-menu'
|
|
||||||
role='menu'
|
|
||||||
>
|
|
||||||
{dropdownContents}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user