Merge branch 'release-3.1'
Conflicts: webapp/components/create_comment.jsx
Этот коммит содержится в:
76
api/oauth.go
76
api/oauth.go
@@ -204,7 +204,10 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case model.OAUTH_ACTION_LOGIN:
|
case model.OAUTH_ACTION_LOGIN:
|
||||||
LoginByOAuth(c, w, r, service, body)
|
user := LoginByOAuth(c, w, r, service, body)
|
||||||
|
if len(teamId) > 0 {
|
||||||
|
c.Err = JoinUserToTeamById(teamId, user)
|
||||||
|
}
|
||||||
if c.Err == nil {
|
if c.Err == nil {
|
||||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
@@ -424,8 +427,17 @@ func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
service := params["service"]
|
service := params["service"]
|
||||||
loginHint := r.URL.Query().Get("login_hint")
|
loginHint := r.URL.Query().Get("login_hint")
|
||||||
|
|
||||||
|
teamId, err := getTeamIdFromQuery(r.URL.Query())
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
stateProps := map[string]string{}
|
stateProps := map[string]string{}
|
||||||
stateProps["action"] = model.OAUTH_ACTION_LOGIN
|
stateProps["action"] = model.OAUTH_ACTION_LOGIN
|
||||||
|
if len(teamId) != 0 {
|
||||||
|
stateProps["team_id"] = teamId
|
||||||
|
}
|
||||||
|
|
||||||
if authUrl, err := GetAuthorizationCode(c, service, stateProps, loginHint); err != nil {
|
if authUrl, err := GetAuthorizationCode(c, service, stateProps, loginHint); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
@@ -435,6 +447,36 @@ func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTeamIdFromQuery(query url.Values) (string, *model.AppError) {
|
||||||
|
hash := query.Get("h")
|
||||||
|
inviteId := query.Get("id")
|
||||||
|
|
||||||
|
if len(hash) > 0 {
|
||||||
|
data := query.Get("d")
|
||||||
|
props := model.MapFromJson(strings.NewReader(data))
|
||||||
|
|
||||||
|
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
|
||||||
|
return "", model.NewLocAppError("getTeamIdFromQuery", "web.singup_with_oauth.invalid_link.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := strconv.ParseInt(props["time"], 10, 64)
|
||||||
|
if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
|
||||||
|
return "", model.NewLocAppError("getTeamIdFromQuery", "web.singup_with_oauth.expired_link.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return props["id"], nil
|
||||||
|
} else if len(inviteId) > 0 {
|
||||||
|
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
|
||||||
|
// soft fail, so we still create user but don't auto-join team
|
||||||
|
l4g.Error("%v", result.Err)
|
||||||
|
} else {
|
||||||
|
return result.Data.(*model.Team).Id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
service := params["service"]
|
service := params["service"]
|
||||||
@@ -445,34 +487,10 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := r.URL.Query().Get("h")
|
teamId, err := getTeamIdFromQuery(r.URL.Query())
|
||||||
|
if err != nil {
|
||||||
teamId := ""
|
c.Err = err
|
||||||
inviteId := r.URL.Query().Get("id")
|
return
|
||||||
|
|
||||||
if len(hash) > 0 {
|
|
||||||
data := r.URL.Query().Get("d")
|
|
||||||
props := model.MapFromJson(strings.NewReader(data))
|
|
||||||
|
|
||||||
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
|
|
||||||
c.Err = model.NewLocAppError("signupWithOAuth", "web.singup_with_oauth.invalid_link.app_error", nil, "")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := strconv.ParseInt(props["time"], 10, 64)
|
|
||||||
if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
|
|
||||||
c.Err = model.NewLocAppError("signupWithOAuth", "web.singup_with_oauth.expired_link.app_error", nil, "")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
teamId = props["id"]
|
|
||||||
} else if len(inviteId) != 0 {
|
|
||||||
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
|
|
||||||
// soft fail, so we still create user but don't auto-join team
|
|
||||||
l4g.Error("%v", result.Err)
|
|
||||||
} else {
|
|
||||||
teamId = result.Data.(*model.Team).Id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stateProps := map[string]string{}
|
stateProps := map[string]string{}
|
||||||
|
|||||||
12
api/team.go
12
api/team.go
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
|
"github.com/mattermost/platform/store"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -247,6 +248,14 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JoinUserToTeamById(teamId string, user *model.User) *model.AppError {
|
||||||
|
if result := <-Srv.Store.Team().Get(teamId); result.Err != nil {
|
||||||
|
return result.Err
|
||||||
|
} else {
|
||||||
|
return JoinUserToTeam(result.Data.(*model.Team), user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
|
func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
|
||||||
|
|
||||||
tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id}
|
tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id}
|
||||||
@@ -258,6 +267,9 @@ func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tmr := <-Srv.Store.Team().SaveMember(tm); tmr.Err != nil {
|
if tmr := <-Srv.Store.Team().SaveMember(tm); tmr.Err != nil {
|
||||||
|
if tmr.Err.Id == store.TEAM_MEMBER_EXISTS_ERROR {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return tmr.Err
|
return tmr.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
api/user.go
23
api/user.go
@@ -285,11 +285,6 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service
|
|||||||
suchan := Srv.Store.User().GetByAuth(user.AuthData, service)
|
suchan := Srv.Store.User().GetByAuth(user.AuthData, service)
|
||||||
euchan := Srv.Store.User().GetByEmail(user.Email)
|
euchan := Srv.Store.User().GetByEmail(user.Email)
|
||||||
|
|
||||||
var tchan store.StoreChannel
|
|
||||||
if len(teamId) != 0 {
|
|
||||||
tchan = Srv.Store.Team().Get(teamId)
|
|
||||||
}
|
|
||||||
|
|
||||||
found := true
|
found := true
|
||||||
count := 0
|
count := 0
|
||||||
for found {
|
for found {
|
||||||
@@ -319,20 +314,14 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tchan != nil {
|
if len(teamId) > 0 {
|
||||||
if result := <-tchan; result.Err != nil {
|
err = JoinUserToTeamById(teamId, user)
|
||||||
c.Err = result.Err
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
return nil
|
return nil
|
||||||
} else {
|
|
||||||
team := result.Data.(*model.Team)
|
|
||||||
err = JoinUserToTeam(team, user)
|
|
||||||
if err != nil {
|
|
||||||
c.Err = err
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
go addDirectChannels(team.Id, user)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go addDirectChannels(teamId, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
doLogin(c, w, r, ruser, "")
|
doLogin(c, w, r, ruser, "")
|
||||||
|
|||||||
@@ -868,6 +868,7 @@ func cmdVersion() {
|
|||||||
fmt.Fprintln(os.Stderr, "Build Date: "+model.BuildDate)
|
fmt.Fprintln(os.Stderr, "Build Date: "+model.BuildDate)
|
||||||
fmt.Fprintln(os.Stderr, "Build Hash: "+model.BuildHash)
|
fmt.Fprintln(os.Stderr, "Build Hash: "+model.BuildHash)
|
||||||
fmt.Fprintln(os.Stderr, "Build Enterprise Ready: "+model.BuildEnterpriseReady)
|
fmt.Fprintln(os.Stderr, "Build Enterprise Ready: "+model.BuildEnterpriseReady)
|
||||||
|
fmt.Fprintln(os.Stderr, "DB Version: "+api.Srv.Store.(*store.SqlStore).SchemaVersion)
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
100
model/config.go
100
model/config.go
@@ -6,6 +6,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -35,6 +36,15 @@ const (
|
|||||||
FAKE_SETTING = "********************************"
|
FAKE_SETTING = "********************************"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// should match the values in webapp/i18n/i18n.jsx
|
||||||
|
var LOCALES = []string{
|
||||||
|
"en",
|
||||||
|
"es",
|
||||||
|
"fr",
|
||||||
|
"ja",
|
||||||
|
"pt-BR",
|
||||||
|
}
|
||||||
|
|
||||||
type ServiceSettings struct {
|
type ServiceSettings struct {
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
MaximumLoginAttempts int
|
MaximumLoginAttempts int
|
||||||
@@ -420,19 +430,39 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.Enable == nil {
|
||||||
|
o.LdapSettings.Enable = new(bool)
|
||||||
|
*o.LdapSettings.Enable = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LdapServer == nil {
|
||||||
|
o.LdapSettings.LdapServer = new(string)
|
||||||
|
*o.LdapSettings.LdapServer = ""
|
||||||
|
}
|
||||||
|
|
||||||
if o.LdapSettings.LdapPort == nil {
|
if o.LdapSettings.LdapPort == nil {
|
||||||
o.LdapSettings.LdapPort = new(int)
|
o.LdapSettings.LdapPort = new(int)
|
||||||
*o.LdapSettings.LdapPort = 389
|
*o.LdapSettings.LdapPort = 389
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.QueryTimeout == nil {
|
if o.LdapSettings.ConnectionSecurity == nil {
|
||||||
o.LdapSettings.QueryTimeout = new(int)
|
o.LdapSettings.ConnectionSecurity = new(string)
|
||||||
*o.LdapSettings.QueryTimeout = 60
|
*o.LdapSettings.ConnectionSecurity = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.Enable == nil {
|
if o.LdapSettings.BaseDN == nil {
|
||||||
o.LdapSettings.Enable = new(bool)
|
o.LdapSettings.BaseDN = new(string)
|
||||||
*o.LdapSettings.Enable = false
|
*o.LdapSettings.BaseDN = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.BindUsername == nil {
|
||||||
|
o.LdapSettings.BindUsername = new(string)
|
||||||
|
*o.LdapSettings.BindUsername = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.BindPassword == nil {
|
||||||
|
o.LdapSettings.BindPassword = new(string)
|
||||||
|
*o.LdapSettings.BindPassword = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.UserFilter == nil {
|
if o.LdapSettings.UserFilter == nil {
|
||||||
@@ -440,9 +470,29 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.LdapSettings.UserFilter = ""
|
*o.LdapSettings.UserFilter = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.LoginFieldName == nil {
|
if o.LdapSettings.FirstNameAttribute == nil {
|
||||||
o.LdapSettings.LoginFieldName = new(string)
|
o.LdapSettings.FirstNameAttribute = new(string)
|
||||||
*o.LdapSettings.LoginFieldName = ""
|
*o.LdapSettings.FirstNameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LastNameAttribute == nil {
|
||||||
|
o.LdapSettings.LastNameAttribute = new(string)
|
||||||
|
*o.LdapSettings.LastNameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.EmailAttribute == nil {
|
||||||
|
o.LdapSettings.EmailAttribute = new(string)
|
||||||
|
*o.LdapSettings.EmailAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.NicknameAttribute == nil {
|
||||||
|
o.LdapSettings.NicknameAttribute = new(string)
|
||||||
|
*o.LdapSettings.NicknameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.IdAttribute == nil {
|
||||||
|
o.LdapSettings.IdAttribute = new(string)
|
||||||
|
*o.LdapSettings.IdAttribute = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.SyncIntervalMinutes == nil {
|
if o.LdapSettings.SyncIntervalMinutes == nil {
|
||||||
@@ -450,6 +500,21 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.LdapSettings.SyncIntervalMinutes = 60
|
*o.LdapSettings.SyncIntervalMinutes = 60
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.SkipCertificateVerification == nil {
|
||||||
|
o.LdapSettings.SkipCertificateVerification = new(bool)
|
||||||
|
*o.LdapSettings.SkipCertificateVerification = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.QueryTimeout == nil {
|
||||||
|
o.LdapSettings.QueryTimeout = new(int)
|
||||||
|
*o.LdapSettings.QueryTimeout = 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LoginFieldName == nil {
|
||||||
|
o.LdapSettings.LoginFieldName = new(string)
|
||||||
|
*o.LdapSettings.LoginFieldName = ""
|
||||||
|
}
|
||||||
|
|
||||||
if o.ServiceSettings.SessionLengthWebInDays == nil {
|
if o.ServiceSettings.SessionLengthWebInDays == nil {
|
||||||
o.ServiceSettings.SessionLengthWebInDays = new(int)
|
o.ServiceSettings.SessionLengthWebInDays = new(int)
|
||||||
*o.ServiceSettings.SessionLengthWebInDays = 30
|
*o.ServiceSettings.SessionLengthWebInDays = 30
|
||||||
@@ -515,21 +580,6 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.ComplianceSettings.EnableDaily = false
|
*o.ComplianceSettings.EnableDaily = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.ConnectionSecurity == nil {
|
|
||||||
o.LdapSettings.ConnectionSecurity = new(string)
|
|
||||||
*o.LdapSettings.ConnectionSecurity = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.LdapSettings.SkipCertificateVerification == nil {
|
|
||||||
o.LdapSettings.SkipCertificateVerification = new(bool)
|
|
||||||
*o.LdapSettings.SkipCertificateVerification = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.LdapSettings.NicknameAttribute == nil {
|
|
||||||
o.LdapSettings.NicknameAttribute = new(string)
|
|
||||||
*o.LdapSettings.NicknameAttribute = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.LocalizationSettings.DefaultServerLocale == nil {
|
if o.LocalizationSettings.DefaultServerLocale == nil {
|
||||||
o.LocalizationSettings.DefaultServerLocale = new(string)
|
o.LocalizationSettings.DefaultServerLocale = new(string)
|
||||||
*o.LocalizationSettings.DefaultServerLocale = DEFAULT_LOCALE
|
*o.LocalizationSettings.DefaultServerLocale = DEFAULT_LOCALE
|
||||||
@@ -542,7 +592,7 @@ func (o *Config) SetDefaults() {
|
|||||||
|
|
||||||
if o.LocalizationSettings.AvailableLocales == nil {
|
if o.LocalizationSettings.AvailableLocales == nil {
|
||||||
o.LocalizationSettings.AvailableLocales = new(string)
|
o.LocalizationSettings.AvailableLocales = new(string)
|
||||||
*o.LocalizationSettings.AvailableLocales = *o.LocalizationSettings.DefaultClientLocale
|
*o.LocalizationSettings.AvailableLocales = strings.Join(LOCALES, ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
// It should be maitained in chronological order with most current
|
// It should be maitained in chronological order with most current
|
||||||
// release at the front of the list.
|
// release at the front of the list.
|
||||||
var versions = []string{
|
var versions = []string{
|
||||||
|
"3.1.0",
|
||||||
"3.0.0",
|
"3.0.0",
|
||||||
"2.2.0",
|
"2.2.0",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import (
|
|||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TEAM_MEMBER_EXISTS_ERROR = "store.sql_team.save_member.exists.app_error"
|
||||||
|
)
|
||||||
|
|
||||||
type SqlTeamStore struct {
|
type SqlTeamStore struct {
|
||||||
*SqlStore
|
*SqlStore
|
||||||
}
|
}
|
||||||
@@ -372,8 +376,8 @@ func (s SqlTeamStore) SaveMember(member *model.TeamMember) StoreChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := s.GetMaster().Insert(member); err != nil {
|
if err := s.GetMaster().Insert(member); err != nil {
|
||||||
if IsUniqueConstraintError(err.Error(), []string{"TeamId", "teammembers_pkey"}) {
|
if IsUniqueConstraintError(err.Error(), []string{"TeamId", "teammembers_pkey", "PRIMARY"}) {
|
||||||
result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.exists.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error())
|
result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", TEAM_MEMBER_EXISTS_ERROR, nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error())
|
||||||
} else {
|
} else {
|
||||||
result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error())
|
result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ export function doFocusPost(channelId, postId, data) {
|
|||||||
});
|
});
|
||||||
AsyncClient.getChannels(true);
|
AsyncClient.getChannels(true);
|
||||||
AsyncClient.getChannelExtraInfo(channelId);
|
AsyncClient.getChannelExtraInfo(channelId);
|
||||||
AsyncClient.getPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS);
|
AsyncClient.getPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
|
||||||
AsyncClient.getPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS);
|
AsyncClient.getPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function emitPostFocusEvent(postId) {
|
export function emitPostFocusEvent(postId) {
|
||||||
|
|||||||
@@ -239,6 +239,22 @@ export default class AdminSidebar extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let customBranding = null;
|
||||||
|
|
||||||
|
if (window.mm_license.IsLicensed === 'true') {
|
||||||
|
customBranding = (
|
||||||
|
<AdminSidebarSection
|
||||||
|
name='custom_brand'
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='admin.sidebar.customBrand'
|
||||||
|
defaultMessage='Custom Branding'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='admin-sidebar'>
|
<div className='admin-sidebar'>
|
||||||
<AdminSidebarHeader/>
|
<AdminSidebarHeader/>
|
||||||
@@ -515,16 +531,7 @@ export default class AdminSidebar extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AdminSidebarSection
|
{customBranding}
|
||||||
name='custom_brand'
|
|
||||||
title={
|
|
||||||
<FormattedMessage
|
|
||||||
id='admin.sidebar.customBrand'
|
|
||||||
defaultMessage='Custom Branding'
|
|
||||||
/>
|
|
||||||
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<AdminSidebarSection
|
<AdminSidebarSection
|
||||||
name='legal_and_support'
|
name='legal_and_support'
|
||||||
title={
|
title={
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ export default class LdapSettings extends AdminSettings {
|
|||||||
helpText={
|
helpText={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='admin.ldap.syncIntervalHelpText'
|
id='admin.ldap.syncIntervalHelpText'
|
||||||
defaultMessage='LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.'
|
defaultMessage='LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour. Changing this will require a server restart before taking effect.'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
value={this.state.syncIntervalMinutes}
|
value={this.state.syncIntervalMinutes}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export default class MultiSelectSetting extends React.Component {
|
|||||||
labelKey='text'
|
labelKey='text'
|
||||||
options={this.props.values}
|
options={this.props.values}
|
||||||
joinValues={true}
|
joinValues={true}
|
||||||
|
clearable={false}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
noResultsText={this.props.noResultText}
|
noResultsText={this.props.noResultText}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ export default class StorageSettings extends AdminSettings {
|
|||||||
|
|
||||||
this.renderSettings = this.renderSettings.bind(this);
|
this.renderSettings = this.renderSettings.bind(this);
|
||||||
|
|
||||||
|
//maxFileSize: props.config.FileSettings.MaxFileSize,
|
||||||
this.state = Object.assign(this.state, {
|
this.state = Object.assign(this.state, {
|
||||||
maxFileSize: props.config.FileSettings.MaxFileSize,
|
|
||||||
driverName: props.config.FileSettings.DriverName,
|
driverName: props.config.FileSettings.DriverName,
|
||||||
directory: props.config.FileSettings.Directory,
|
directory: props.config.FileSettings.Directory,
|
||||||
amazonS3AccessKeyId: props.config.FileSettings.AmazonS3AccessKeyId,
|
amazonS3AccessKeyId: props.config.FileSettings.AmazonS3AccessKeyId,
|
||||||
@@ -34,7 +34,7 @@ export default class StorageSettings extends AdminSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getConfigFromState(config) {
|
getConfigFromState(config) {
|
||||||
config.FileSettings.MaxFileSize = this.parseInt(this.state.maxFileSize);
|
//config.FileSettings.MaxFileSize = this.parseInt(this.state.maxFileSize);
|
||||||
config.FileSettings.DriverName = this.state.driverName;
|
config.FileSettings.DriverName = this.state.driverName;
|
||||||
config.FileSettings.Directory = this.state.directory;
|
config.FileSettings.Directory = this.state.directory;
|
||||||
config.FileSettings.AmazonS3AccessKeyId = this.state.amazonS3AccessKeyId;
|
config.FileSettings.AmazonS3AccessKeyId = this.state.amazonS3AccessKeyId;
|
||||||
@@ -57,26 +57,27 @@ export default class StorageSettings extends AdminSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderSettings() {
|
renderSettings() {
|
||||||
|
/*<TextSetting
|
||||||
|
id='maxFileSize'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='admin.image.maxFileSizeTitle'
|
||||||
|
defaultMessage='Max File Size:'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
placeholder={Utils.localizeMessage('admin.image.maxFileSizeExample', 'Ex "52428800"')}
|
||||||
|
helpText={
|
||||||
|
<FormattedMessage
|
||||||
|
id='admin.image.maxFileSizeDescription'
|
||||||
|
defaultMessage='Max File Size in bytes. If blank, will be set to 52428800 (50MB).'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={this.state.maxFileSize}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>*/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsGroup>
|
<SettingsGroup>
|
||||||
<TextSetting
|
|
||||||
id='maxFileSize'
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id='admin.image.maxFileSizeTitle'
|
|
||||||
defaultMessage='Max File Size:'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
placeholder={Utils.localizeMessage('admin.image.maxFileSizeExample', 'Ex "52428800"')}
|
|
||||||
helpText={
|
|
||||||
<FormattedMessage
|
|
||||||
id='admin.image.maxFileSizeDescription'
|
|
||||||
defaultMessage='Max File Size in bytes. If blank, will be set to 52428800 (50MB).'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
value={this.state.maxFileSize}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
/>
|
|
||||||
<DropdownSetting
|
<DropdownSetting
|
||||||
id='driverName'
|
id='driverName'
|
||||||
values={[
|
values={[
|
||||||
|
|||||||
@@ -23,26 +23,26 @@ export default class DoughnutChart extends React.Component {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!Utils.areObjectsEqual(prevProps.data, this.props.data) || !Utils.areObjectsEqual(prevProps.options, this.props.options)) {
|
if (!Utils.areObjectsEqual(prevProps.data, this.props.data) || !Utils.areObjectsEqual(prevProps.options, this.props.options)) {
|
||||||
if (this.chart) {
|
this.initChart(true);
|
||||||
this.chart.destroy();
|
|
||||||
}
|
|
||||||
this.initChart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.chart) {
|
if (this.chart && this.refs.canvas) {
|
||||||
this.chart.destroy();
|
this.chart.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initChart() {
|
initChart(update) {
|
||||||
if (!this.refs.canvas) {
|
if (!this.refs.canvas) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var el = ReactDOM.findDOMNode(this.refs.canvas);
|
var el = ReactDOM.findDOMNode(this.refs.canvas);
|
||||||
var ctx = el.getContext('2d');
|
var ctx = el.getContext('2d');
|
||||||
this.chart = new Chart(ctx, {type: 'doughnut', data: this.props.data, options: this.props.options || {}}); //eslint-disable-line new-cap
|
this.chart = new Chart(ctx, {type: 'doughnut', data: this.props.data, options: this.props.options || {}}); //eslint-disable-line new-cap
|
||||||
|
if (update) {
|
||||||
|
this.chart.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -23,26 +23,26 @@ export default class LineChart extends React.Component {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!Utils.areObjectsEqual(prevProps.data, this.props.data) || !Utils.areObjectsEqual(prevProps.options, this.props.options)) {
|
if (!Utils.areObjectsEqual(prevProps.data, this.props.data) || !Utils.areObjectsEqual(prevProps.options, this.props.options)) {
|
||||||
if (this.chart) {
|
this.initChart(true);
|
||||||
this.chart.destroy();
|
|
||||||
}
|
|
||||||
this.initChart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.chart) {
|
if (this.chart && this.refs.canvas) {
|
||||||
this.chart.destroy();
|
this.chart.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initChart() {
|
initChart(update) {
|
||||||
if (!this.refs.canvas) {
|
if (!this.refs.canvas) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var el = ReactDOM.findDOMNode(this.refs.canvas);
|
var el = ReactDOM.findDOMNode(this.refs.canvas);
|
||||||
var ctx = el.getContext('2d');
|
var ctx = el.getContext('2d');
|
||||||
this.chart = new Chart(ctx, {type: 'line', data: this.props.data, options: this.props.options || {}}); //eslint-disable-line new-cap
|
this.chart = new Chart(ctx, {type: 'line', data: this.props.data, options: this.props.options || {}}); //eslint-disable-line new-cap
|
||||||
|
if (update) {
|
||||||
|
this.chart.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class CreateComment extends React.Component {
|
|||||||
Client.createPost(
|
Client.createPost(
|
||||||
post,
|
post,
|
||||||
() => {
|
() => {
|
||||||
// DO nothing. Websockets will handle this.
|
PostStore.removePendingPost(post.channel_id, post.pending_post_id);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err.id === 'api.post.create_post.root_id.app_error') {
|
if (err.id === 'api.post.create_post.root_id.app_error') {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ class CreatePost extends React.Component {
|
|||||||
|
|
||||||
Client.createPost(post,
|
Client.createPost(post,
|
||||||
() => {
|
() => {
|
||||||
// DO nothing. Websockets will handle this.
|
PostStore.removePendingPost(post.pending_post_id);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err.id === 'api.post.create_post.root_id.app_error') {
|
if (err.id === 'api.post.create_post.root_id.app_error') {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class EditPostModal extends React.Component {
|
|||||||
Client.updatePost(
|
Client.updatePost(
|
||||||
updatedPost,
|
updatedPost,
|
||||||
() => {
|
() => {
|
||||||
|
AsyncClient.getPosts(updatedPost.channel_id);
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
|
|||||||
@@ -69,13 +69,13 @@ export default class LoginController extends React.Component {
|
|||||||
this.setState({loginId});
|
this.setState({loginId});
|
||||||
}
|
}
|
||||||
|
|
||||||
let password = this.refs.password.value;
|
const password = this.refs.password.value;
|
||||||
if (password !== this.state.password) {
|
if (password !== this.state.password) {
|
||||||
this.setState({password});
|
this.setState({password});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't trim the password since we support spaces in passwords
|
||||||
loginId = loginId.trim();
|
loginId = loginId.trim();
|
||||||
password = password.trim();
|
|
||||||
|
|
||||||
if (!loginId) {
|
if (!loginId) {
|
||||||
// it's slightly weird to be constructing the message ID, but it's a bit nicer than triply nested if statements
|
// it's slightly weird to be constructing the message ID, but it's a bit nicer than triply nested if statements
|
||||||
@@ -444,7 +444,7 @@ export default class LoginController extends React.Component {
|
|||||||
<a
|
<a
|
||||||
className='btn btn-custom-login gitlab'
|
className='btn btn-custom-login gitlab'
|
||||||
key='gitlab'
|
key='gitlab'
|
||||||
href={Client.getOAuthRoute() + '/gitlab/login'}
|
href={Client.getOAuthRoute() + '/gitlab/login' + this.props.location.search}
|
||||||
>
|
>
|
||||||
<span className='icon'/>
|
<span className='icon'/>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ export default class RhsRootPost extends React.Component {
|
|||||||
filenames={post.filenames}
|
filenames={post.filenames}
|
||||||
channelId={post.channel_id}
|
channelId={post.channel_id}
|
||||||
userId={post.user_id}
|
userId={post.user_id}
|
||||||
|
compactDisplay={this.props.compactDisplay}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,11 +173,24 @@ export default class SignupUserComplete extends React.Component {
|
|||||||
this.state.ldapPassword,
|
this.state.ldapPassword,
|
||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
GlobalActions.emitInitialLoad(
|
if (this.props.location.query.id || this.props.location.query.h) {
|
||||||
() => {
|
Client.addUserToTeamFromInvite(
|
||||||
browserHistory.push('/select_team');
|
this.props.location.query.d,
|
||||||
}
|
this.props.location.query.h,
|
||||||
);
|
this.props.location.query.id,
|
||||||
|
() => {
|
||||||
|
this.finishSignup();
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// there's not really a good way to deal with this, so just let the user log in like normal
|
||||||
|
this.finishSignup();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.finishSignup();
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err.id === 'ent.ldap.do_login.user_not_registered.app_error' || err.id === 'ent.ldap.do_login.user_filtered.app_error') {
|
if (err.id === 'ent.ldap.do_login.user_not_registered.app_error' || err.id === 'ent.ldap.do_login.user_filtered.app_error') {
|
||||||
@@ -205,6 +218,15 @@ export default class SignupUserComplete extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finishSignup() {
|
||||||
|
GlobalActions.emitInitialLoad(
|
||||||
|
() => {
|
||||||
|
GlobalActions.loadDefaultLocale();
|
||||||
|
browserHistory.push('/select_team');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
handleUserCreated(user, data) {
|
handleUserCreated(user, data) {
|
||||||
track('signup', 'signup_user_02_complete');
|
track('signup', 'signup_user_02_complete');
|
||||||
Client.loginById(
|
Client.loginById(
|
||||||
|
|||||||
@@ -181,6 +181,7 @@
|
|||||||
"admin.email.smtpUsernameTitle": "SMTP Username:",
|
"admin.email.smtpUsernameTitle": "SMTP Username:",
|
||||||
"admin.email.testing": "Testing...",
|
"admin.email.testing": "Testing...",
|
||||||
"admin.false": "false",
|
"admin.false": "false",
|
||||||
|
"admin.general.localization": "Localization",
|
||||||
"admin.general.localization.availableLocalesDescription": "Determines which languages are available for users in Account Settings.",
|
"admin.general.localization.availableLocalesDescription": "Determines which languages are available for users in Account Settings.",
|
||||||
"admin.general.localization.clientLocaleDescription": "Default language for newly created users and pages where the user hasn't logged in.",
|
"admin.general.localization.clientLocaleDescription": "Default language for newly created users and pages where the user hasn't logged in.",
|
||||||
"admin.general.localization.serverLocaleDescription": "Default language for system messages and logs. Changing this will require a server restart before taking effect.",
|
"admin.general.localization.serverLocaleDescription": "Default language for system messages and logs. Changing this will require a server restart before taking effect.",
|
||||||
@@ -283,7 +284,7 @@
|
|||||||
"admin.ldap.serverTitle": "LDAP Server:",
|
"admin.ldap.serverTitle": "LDAP Server:",
|
||||||
"admin.ldap.skipCertificateVerification": "Skip Certificate Verification",
|
"admin.ldap.skipCertificateVerification": "Skip Certificate Verification",
|
||||||
"admin.ldap.skipCertificateVerificationDesc": "Skips the certificate verification step for TLS or STARTTLS connections. Not recommended for production environments where TLS is required. For testing only.",
|
"admin.ldap.skipCertificateVerificationDesc": "Skips the certificate verification step for TLS or STARTTLS connections. Not recommended for production environments where TLS is required. For testing only.",
|
||||||
"admin.ldap.syncIntervalHelpText": "LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.",
|
"admin.ldap.syncIntervalHelpText": "LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour. Changing this will require a server restart before taking effect.",
|
||||||
"admin.ldap.syncIntervalTitle": "Synchronization Interval (In Minutes)",
|
"admin.ldap.syncIntervalTitle": "Synchronization Interval (In Minutes)",
|
||||||
"admin.ldap.uernameAttrDesc": "The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.",
|
"admin.ldap.uernameAttrDesc": "The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.",
|
||||||
"admin.ldap.userFilterDisc": "Optionally enter an LDAP Filter to use when searching for user objects. Only the users selected by the query will be able to access Mattermost. For Active Directory, the query to filter out disabled users is (&(objectCategory=Person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))).",
|
"admin.ldap.userFilterDisc": "Optionally enter an LDAP Filter to use when searching for user objects. Only the users selected by the query will be able to access Mattermost. For Active Directory, the query to filter out disabled users is (&(objectCategory=Person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))).",
|
||||||
@@ -433,6 +434,7 @@
|
|||||||
"admin.sidebar.integrations": "Integrations",
|
"admin.sidebar.integrations": "Integrations",
|
||||||
"admin.sidebar.ldap": "LDAP",
|
"admin.sidebar.ldap": "LDAP",
|
||||||
"admin.sidebar.license": "Edition and License",
|
"admin.sidebar.license": "Edition and License",
|
||||||
|
"admin.sidebar.localization": "Localization",
|
||||||
"admin.sidebar.logging": "Logging",
|
"admin.sidebar.logging": "Logging",
|
||||||
"admin.sidebar.login": "Login",
|
"admin.sidebar.login": "Login",
|
||||||
"admin.sidebar.logs": "Logs",
|
"admin.sidebar.logs": "Logs",
|
||||||
|
|||||||
@@ -181,6 +181,7 @@
|
|||||||
"admin.email.smtpUsernameTitle": "Usuario SMTP:",
|
"admin.email.smtpUsernameTitle": "Usuario SMTP:",
|
||||||
"admin.email.testing": "Probando...",
|
"admin.email.testing": "Probando...",
|
||||||
"admin.false": "falso",
|
"admin.false": "falso",
|
||||||
|
"admin.general.localization": "Idiomas",
|
||||||
"admin.general.localization.availableLocalesDescription": "Determina qué idiomas están disponibles para los usuarios en la Configuración de la Cuenta.",
|
"admin.general.localization.availableLocalesDescription": "Determina qué idiomas están disponibles para los usuarios en la Configuración de la Cuenta.",
|
||||||
"admin.general.localization.clientLocaleDescription": "Idioma predeterminado para nuevos usuarios y páginas donde el usuario no ha iniciado sesión.",
|
"admin.general.localization.clientLocaleDescription": "Idioma predeterminado para nuevos usuarios y páginas donde el usuario no ha iniciado sesión.",
|
||||||
"admin.general.localization.serverLocaleDescription": "Idioma predeterminado para los mensajes del sistema y los registros. Cambiar esto requerirá un reinicio del servidor antes de tomar efecto.",
|
"admin.general.localization.serverLocaleDescription": "Idioma predeterminado para los mensajes del sistema y los registros. Cambiar esto requerirá un reinicio del servidor antes de tomar efecto.",
|
||||||
@@ -431,6 +432,7 @@
|
|||||||
"admin.sidebar.integrations": "Integraciones",
|
"admin.sidebar.integrations": "Integraciones",
|
||||||
"admin.sidebar.ldap": "LDAP",
|
"admin.sidebar.ldap": "LDAP",
|
||||||
"admin.sidebar.license": "Edición y Licencia",
|
"admin.sidebar.license": "Edición y Licencia",
|
||||||
|
"admin.sidebar.localization": "Idiomas",
|
||||||
"admin.sidebar.logging": "Registros",
|
"admin.sidebar.logging": "Registros",
|
||||||
"admin.sidebar.login": "Inicio de Sesión",
|
"admin.sidebar.login": "Inicio de Sesión",
|
||||||
"admin.sidebar.logs": "Registros",
|
"admin.sidebar.logs": "Registros",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import frLocaleData from 'react-intl/locale-data/fr';
|
|||||||
import jaLocaleData from 'react-intl/locale-data/ja';
|
import jaLocaleData from 'react-intl/locale-data/ja';
|
||||||
import ptLocaleData from 'react-intl/locale-data/pt';
|
import ptLocaleData from 'react-intl/locale-data/pt';
|
||||||
|
|
||||||
|
// should match the values in model/config.go
|
||||||
const languages = {
|
const languages = {
|
||||||
en: {
|
en: {
|
||||||
value: 'en',
|
value: 'en',
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"keymirror": "0.1.1",
|
"keymirror": "0.1.1",
|
||||||
"marked": "mattermost/marked#2d92082cd542dc0adc175a1407194f6a4c3cb621",
|
"marked": "mattermost/marked#2d92082cd542dc0adc175a1407194f6a4c3cb621",
|
||||||
"match-at": "0.1.0",
|
"match-at": "0.1.0",
|
||||||
"mattermost": "mattermost/mattermost-javascript#master",
|
"mattermost": "mattermost/mattermost-javascript#release-3.1",
|
||||||
"object-assign": "4.1.0",
|
"object-assign": "4.1.0",
|
||||||
"perfect-scrollbar": "0.6.11",
|
"perfect-scrollbar": "0.6.11",
|
||||||
"react": "15.0.2",
|
"react": "15.0.2",
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
@include clearfix;
|
@include clearfix;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
height: 36px;
|
height: 39px;
|
||||||
line-height: 36px;
|
line-height: 35px;
|
||||||
margin: 5px 0;
|
margin: 0;
|
||||||
padding: 2px;
|
padding: 3px 8px;
|
||||||
position: relative;
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -552,7 +552,7 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
|
|||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.RECEIVED_POSTS: {
|
case ActionTypes.RECEIVED_POSTS: {
|
||||||
const id = PostStore.currentFocusedPostId == null ? action.id : PostStore.currentFocusedPostId;
|
const id = PostStore.currentFocusedPostId !== null && action.isPost ? PostStore.currentFocusedPostId : action.id;
|
||||||
PostStore.storePosts(id, makePostListNonNull(action.post_list));
|
PostStore.storePosts(id, makePostListNonNull(action.post_list));
|
||||||
PostStore.checkBounds(id, action.numRequested, makePostListNonNull(action.post_list), action.before);
|
PostStore.checkBounds(id, action.numRequested, makePostListNonNull(action.post_list), action.before);
|
||||||
PostStore.emitChange();
|
PostStore.emitChange();
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class UserStoreClass extends EventEmitter {
|
|||||||
this.currentUserId = user.id;
|
this.currentUserId = user.id;
|
||||||
global.window.mm_current_user_id = this.currentUserId;
|
global.window.mm_current_user_id = this.currentUserId;
|
||||||
if (LocalizationStore.getLocale() !== user.locale) {
|
if (LocalizationStore.getLocale() !== user.locale) {
|
||||||
GlobalActions.newLocalizationSelected(user.locale);
|
setTimeout(() => GlobalActions.newLocalizationSelected(user.locale), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ export function getPosts(id) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPostsBefore(postId, offset, numPost) {
|
export function getPostsBefore(postId, offset, numPost, isPost) {
|
||||||
const channelId = ChannelStore.getCurrentId();
|
const channelId = ChannelStore.getCurrentId();
|
||||||
if (channelId == null) {
|
if (channelId == null) {
|
||||||
return;
|
return;
|
||||||
@@ -624,7 +624,8 @@ export function getPostsBefore(postId, offset, numPost) {
|
|||||||
id: channelId,
|
id: channelId,
|
||||||
before: true,
|
before: true,
|
||||||
numRequested: numPost,
|
numRequested: numPost,
|
||||||
post_list: data
|
post_list: data,
|
||||||
|
isPost
|
||||||
});
|
});
|
||||||
|
|
||||||
getProfiles();
|
getProfiles();
|
||||||
@@ -638,7 +639,7 @@ export function getPostsBefore(postId, offset, numPost) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPostsAfter(postId, offset, numPost) {
|
export function getPostsAfter(postId, offset, numPost, isPost) {
|
||||||
const channelId = ChannelStore.getCurrentId();
|
const channelId = ChannelStore.getCurrentId();
|
||||||
if (channelId == null) {
|
if (channelId == null) {
|
||||||
return;
|
return;
|
||||||
@@ -659,7 +660,8 @@ export function getPostsAfter(postId, offset, numPost) {
|
|||||||
id: channelId,
|
id: channelId,
|
||||||
before: false,
|
before: false,
|
||||||
numRequested: numPost,
|
numRequested: numPost,
|
||||||
post_list: data
|
post_list: data,
|
||||||
|
isPost
|
||||||
});
|
});
|
||||||
|
|
||||||
getProfiles();
|
getProfiles();
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class MattermostMarkdownRenderer extends marked.Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove any links added to the text by hashtag or mention parsing since they'll break this link
|
// remove any links added to the text by hashtag or mention parsing since they'll break this link
|
||||||
output += '>' + text.replace(/<\/?a[^>]*>/, '') + '</a>';
|
output += '>' + text.replace(/<\/?a[^>]*>/g, '') + '</a>';
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user