summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/context.go1
-rw-r--r--api/user.go45
-rw-r--r--api/user_test.go28
-rw-r--r--i18n/en.json4
-rw-r--r--model/client.go11
-rw-r--r--model/search_params.go18
-rw-r--r--model/search_params_test.go10
-rw-r--r--model/utils.go10
-rw-r--r--model/utils_test.go41
-rw-r--r--store/sql_session_store.go18
-rw-r--r--store/sql_session_store_test.go22
-rw-r--r--store/store.go1
-rw-r--r--web/react/components/activity_log_modal.jsx9
-rw-r--r--web/react/components/login.jsx27
-rw-r--r--web/react/pages/channel.jsx17
-rw-r--r--web/react/stores/channel_store.jsx56
-rw-r--r--web/react/stores/preference_store.jsx21
-rw-r--r--web/templates/channel.html2
-rw-r--r--web/templates/claim_account.html18
-rw-r--r--web/templates/docs.html3
-rw-r--r--web/templates/find_team.html3
-rw-r--r--web/templates/head.html5
-rw-r--r--web/templates/login.html2
-rw-r--r--web/templates/password_reset.html16
-rw-r--r--web/templates/verify.html11
-rw-r--r--web/templates/welcome.html37
-rw-r--r--web/web.go9
27 files changed, 310 insertions, 135 deletions
diff --git a/api/context.go b/api/context.go
index 41a52fa0c..b91981ecd 100644
--- a/api/context.go
+++ b/api/context.go
@@ -45,6 +45,7 @@ type Page struct {
User *model.User
Team *model.Team
Channel *model.Channel
+ Preferences *model.Preferences
PostID string
SessionTokenIndex int64
Locale string
diff --git a/api/user.go b/api/user.go
index 473f0da54..ceaf1fc2d 100644
--- a/api/user.go
+++ b/api/user.go
@@ -48,6 +48,7 @@ func InitUser(r *mux.Router) {
sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST")
sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
+ sr.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST")
sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST")
sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST")
@@ -546,7 +547,6 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User,
}
}
}
-
} else {
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays)
}
@@ -718,6 +718,49 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(props)))
}
+func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) {
+ props := model.MapFromJson(r.Body)
+
+ deviceId := props["device_id"]
+ if len(deviceId) == 0 {
+ c.SetInvalidParam("attachDevice", "deviceId")
+ return
+ }
+
+ if !(strings.HasPrefix(deviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(deviceId, model.PUSH_NOTIFY_ANDROID+":")) {
+ c.SetInvalidParam("attachDevice", "deviceId")
+ return
+ }
+
+ // A special case where we logout of all other sessions with the same Id
+ if result := <-Srv.Store.Session().GetSessions(c.Session.UserId); result.Err != nil {
+ c.Err = result.Err
+ c.Err.StatusCode = http.StatusForbidden
+ return
+ } else {
+ sessions := result.Data.([]*model.Session)
+ for _, session := range sessions {
+ if session.DeviceId == deviceId && session.Id != c.Session.Id {
+ l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, c.Session.UserId)
+ RevokeSessionById(c, session.Id)
+ if c.Err != nil {
+ c.LogError(c.Err)
+ c.Err = nil
+ }
+ }
+ }
+ }
+
+ sessionCache.Remove(c.Session.Token)
+
+ if result := <-Srv.Store.Session().UpdateDeviceId(c.Session.Id, deviceId); result.Err != nil {
+ c.Err = result.Err
+ return
+ }
+
+ w.Write([]byte(deviceId))
+}
+
func RevokeSessionById(c *Context, sessionId string) {
if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
c.Err = result.Err
diff --git a/api/user_test.go b/api/user_test.go
index 9a172805a..5f85bda0f 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -734,6 +734,34 @@ func TestUserUpdateRoles(t *testing.T) {
}
}
+func TestUserUpdateDeviceId(t *testing.T) {
+ Setup()
+
+ team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
+
+ user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
+ user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
+ store.Must(Srv.Store.User().VerifyEmail(user.Id))
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+ deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
+
+ if _, err := Client.AttachDeviceId(deviceId); err != nil {
+ t.Fatal(err)
+ }
+
+ if result := <-Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ sessions := result.Data.([]*model.Session)
+
+ if sessions[0].DeviceId != deviceId {
+ t.Fatal("Missing device Id")
+ }
+ }
+}
+
func TestUserUpdateActive(t *testing.T) {
Setup()
diff --git a/i18n/en.json b/i18n/en.json
index 72863acd9..14a2e3148 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -2772,6 +2772,10 @@
"translation": "We couldn't update the roles"
},
{
+ "id": "store.sql_session.update_device_id.app_error",
+ "translation": "We couldn't update the device id"
+ },
+ {
"id": "store.sql_system.get.app_error",
"translation": "We encountered an error finding the system properties"
},
diff --git a/model/client.go b/model/client.go
index 8021c7039..d31ac1592 100644
--- a/model/client.go
+++ b/model/client.go
@@ -775,6 +775,17 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
}
}
+func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
+ data := make(map[string]string)
+ data["device_id"] = deviceId
+ if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
+ return nil, err
+ } else {
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
data := make(map[string]string)
data["user_id"] = userId
diff --git a/model/search_params.go b/model/search_params.go
index 17a64d980..9a7406a07 100644
--- a/model/search_params.go
+++ b/model/search_params.go
@@ -20,12 +20,7 @@ func splitWordsNoQuotes(text string) []string {
words := []string{}
for _, word := range strings.Fields(text) {
- word = puncStart.ReplaceAllString(word, "")
- word = puncEnd.ReplaceAllString(word, "")
-
- if len(word) != 0 {
- words = append(words, word)
- }
+ words = append(words, word)
}
return words
@@ -94,7 +89,16 @@ func parseSearchFlags(input []string) ([]string, [][2]string) {
}
if !isFlag {
- words = append(words, word)
+ // trim off surrounding punctuation
+ word = puncStart.ReplaceAllString(word, "")
+ word = puncEnd.ReplaceAllString(word, "")
+
+ // and remove extra pound #s
+ word = hashtagStart.ReplaceAllString(word, "#")
+
+ if len(word) != 0 {
+ words = append(words, word)
+ }
}
}
diff --git a/model/search_params_test.go b/model/search_params_test.go
index af4cbe595..59eb0a113 100644
--- a/model/search_params_test.go
+++ b/model/search_params_test.go
@@ -118,19 +118,19 @@ func TestParseSearchFlags(t *testing.T) {
t.Fatalf("got incorrect flags %v", flags)
}
- if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit:" || words[1] != "cherry" {
+ if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit" || words[1] != "cherry" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
- if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel:" {
+ if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
- if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from:" {
+ if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 2 || flags[0][0] != "channel" || flags[0][1] != "first" || flags[1][0] != "in" || flags[1][1] != "second" {
t.Fatalf("got incorrect flags %v", flags)
@@ -212,4 +212,8 @@ func TestParseSearchParams(t *testing.T) {
if sp := ParseSearchParams("testing in:channel from:someone"); len(sp) != 1 || sp[0].Terms != "testing" || len(sp[0].InChannels) != 1 || sp[0].InChannels[0] != "channel" || len(sp[0].FromUsers) != 1 || sp[0].FromUsers[0] != "someone" {
t.Fatalf("Incorrect output from parse search params: %v", sp[0])
}
+
+ if sp := ParseSearchParams("##hashtag +#plus+"); len(sp) != 1 || sp[0].Terms != "#hashtag #plus" || sp[0].IsHashtag != true || len(sp[0].InChannels) != 0 || len(sp[0].FromUsers) != 0 {
+ t.Fatalf("Incorrect output from parse search params: %v", sp[0])
+ }
}
diff --git a/model/utils.go b/model/utils.go
index 70b7e3bbd..719a2ad1b 100644
--- a/model/utils.go
+++ b/model/utils.go
@@ -298,8 +298,9 @@ func Etag(parts ...interface{}) string {
}
var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
-var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\]+`)
-var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}';\\]+$`)
+var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\<>\-+=%^*|]+`)
+var hashtagStart = regexp.MustCompile(`^#{2,}`)
+var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^*|]+$`)
func ParseHashtags(text string) (string, string) {
words := strings.Fields(text)
@@ -307,8 +308,13 @@ func ParseHashtags(text string) (string, string) {
hashtagString := ""
plainString := ""
for _, word := range words {
+ // trim off surrounding punctuation
word = puncStart.ReplaceAllString(word, "")
word = puncEnd.ReplaceAllString(word, "")
+
+ // and remove extra pound #s
+ word = hashtagStart.ReplaceAllString(word, "#")
+
if validHashtag.MatchString(word) {
hashtagString += " " + word
} else {
diff --git a/model/utils_test.go b/model/utils_test.go
index 24ee4b7a6..b8eabe264 100644
--- a/model/utils_test.go
+++ b/model/utils_test.go
@@ -83,19 +83,34 @@ func TestEtag(t *testing.T) {
}
var hashtags map[string]string = map[string]string{
- "#test": "#test",
- "test": "",
- "#test123": "#test123",
- "#123test123": "",
- "#test-test": "#test-test",
- "#test?": "#test",
- "hi #there": "#there",
- "#bug #idea": "#bug #idea",
- "#bug or #gif!": "#bug #gif",
- "#hüllo": "#hüllo",
- "#?test": "",
- "#-test": "",
- "#yo_yo": "#yo_yo",
+ "#test": "#test",
+ "test": "",
+ "#test123": "#test123",
+ "#123test123": "",
+ "#test-test": "#test-test",
+ "#test?": "#test",
+ "hi #there": "#there",
+ "#bug #idea": "#bug #idea",
+ "#bug or #gif!": "#bug #gif",
+ "#hüllo": "#hüllo",
+ "#?test": "",
+ "#-test": "",
+ "#yo_yo": "#yo_yo",
+ "(#brakets)": "#brakets",
+ ")#stekarb(": "#stekarb",
+ "<#less_than<": "#less_than",
+ ">#greater_than>": "#greater_than",
+ "-#minus-": "#minus",
+ "+#plus+": "#plus",
+ "=#equals=": "#equals",
+ "%#pct%": "#pct",
+ "&#and&": "#and",
+ "^#hat^": "#hat",
+ "##brown#": "#brown",
+ "*#star*": "#star",
+ "|#pipe|": "#pipe",
+ ":#colon:": "#colon",
+ ";#semi;": "#semi",
}
func TestParseHashtags(t *testing.T) {
diff --git a/store/sql_session_store.go b/store/sql_session_store.go
index 4762a1dfd..6532947f4 100644
--- a/store/sql_session_store.go
+++ b/store/sql_session_store.go
@@ -232,3 +232,21 @@ func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
return storeChannel
}
+
+func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel {
+ storeChannel := make(StoreChannel)
+
+ go func() {
+ result := StoreResult{}
+ if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil {
+ result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, "")
+ } else {
+ result.Data = deviceId
+ }
+
+ storeChannel <- result
+ close(storeChannel)
+ }()
+
+ return storeChannel
+}
diff --git a/store/sql_session_store_test.go b/store/sql_session_store_test.go
index cec8e93b0..34d3128a6 100644
--- a/store/sql_session_store_test.go
+++ b/store/sql_session_store_test.go
@@ -157,6 +157,28 @@ func TestSessionRemoveToken(t *testing.T) {
}
}
+func TestSessionUpdateDeviceId(t *testing.T) {
+ Setup()
+
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ s1.TeamId = model.NewId()
+ Must(store.Session().Save(&s1))
+
+ if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ }
+
+ s2 := model.Session{}
+ s2.UserId = model.NewId()
+ s2.TeamId = model.NewId()
+ Must(store.Session().Save(&s2))
+
+ if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil {
+ t.Fatal(rs2.Err)
+ }
+}
+
func TestSessionStoreUpdateLastActivityAt(t *testing.T) {
Setup()
diff --git a/store/store.go b/store/store.go
index b91b08f27..3988f0c6a 100644
--- a/store/store.go
+++ b/store/store.go
@@ -137,6 +137,7 @@ type SessionStore interface {
PermanentDeleteSessionsByUser(teamId string) StoreChannel
UpdateLastActivityAt(sessionId string, time int64) StoreChannel
UpdateRoles(userId string, roles string) StoreChannel
+ UpdateDeviceId(id string, deviceId string) StoreChannel
}
type AuditStore interface {
diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx
index 6a880f0ee..eec4d8f8d 100644
--- a/web/react/components/activity_log_modal.jsx
+++ b/web/react/components/activity_log_modal.jsx
@@ -100,12 +100,15 @@ export default class ActivityLogModal extends React.Component {
if (currentSession.props.platform === 'Windows') {
devicePicture = 'fa fa-windows';
+ } else if (currentSession.device_id.indexOf('apple:') === 0) {
+ devicePicture = 'fa fa-apple';
+ devicePlatform = 'iPhone Native App';
+ } else if (currentSession.device_id.indexOf('android:') === 0) {
+ devicePlatform = 'Android Native App';
+ devicePicture = 'fa fa-android';
} else if (currentSession.props.platform === 'Macintosh' ||
currentSession.props.platform === 'iPhone') {
devicePicture = 'fa fa-apple';
- } else if (currentSession.props.platform.browser.indexOf('Mattermost/') === 0) {
- devicePicture = 'fa fa-apple';
- devicePlatform = 'iPhone';
} else if (currentSession.props.platform === 'Linux') {
if (currentSession.props.os.indexOf('Android') >= 0) {
devicePlatform = 'Android';
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index 6887489a7..3c1d66334 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -115,7 +115,7 @@ export default class Login extends React.Component {
}
let teamSignUp = null;
- if (global.window.mm_config.EnableTeamCreation === 'true') {
+ if (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp()) {
teamSignUp = (
<div className='margin--extra'>
<a
@@ -137,6 +137,21 @@ export default class Login extends React.Component {
);
}
+ let findTeams = null;
+ if (!Utils.isMobileApp()) {
+ findTeams = (
+ <div className='form-group margin--extra form-group--small'>
+ <span>
+ <a href='/find_team'>
+ <FormattedMessage
+ id='login.find_teams'
+ defaultMessage='Find your other teams'
+ />
+ </a></span>
+ </div>
+ );
+ }
+
return (
<div className='signup-team__container'>
<h5 className='margin--less'>{'Sign in to:'}</h5>
@@ -147,15 +162,7 @@ export default class Login extends React.Component {
{emailSignup}
{ldapLogin}
{userSignUp}
- <div className='form-group margin--extra form-group--small'>
- <span>
- <a href='/find_team'>
- <FormattedMessage
- id='login.find_teams'
- defaultMessage='Find your other teams'
- />
- </a></span>
- </div>
+ {findTeams}
{forgotPassword}
{teamSignUp}
</div>
diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx
index 1e28dab8b..bfb95e1fc 100644
--- a/web/react/pages/channel.jsx
+++ b/web/react/pages/channel.jsx
@@ -18,14 +18,8 @@ import RegisterAppModal from '../components/register_app_modal.jsx';
import ImportThemeModal from '../components/user_settings/import_theme_modal.jsx';
import InviteMemberModal from '../components/invite_member_modal.jsx';
-import PreferenceStore from '../stores/preference_store.jsx';
-
-import * as Utils from '../utils/utils.jsx';
-import * as AsyncClient from '../utils/async_client.jsx';
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
-import Constants from '../utils/constants.jsx';
-
var IntlProvider = ReactIntl.IntlProvider;
class Root extends React.Component {
@@ -92,12 +86,6 @@ class Root extends React.Component {
}
}
-function onPreferenceChange() {
- const selectedFont = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT);
- Utils.applyFont(selectedFont);
- PreferenceStore.removeChangeListener(onPreferenceChange);
-}
-
global.window.setup_channel_page = function setup(props, team, channel) {
if (props.PostId === '') {
EventHelpers.emitChannelClickEvent(channel);
@@ -105,11 +93,8 @@ global.window.setup_channel_page = function setup(props, team, channel) {
EventHelpers.emitPostFocusEvent(props.PostId);
}
- PreferenceStore.addChangeListener(onPreferenceChange);
- AsyncClient.getAllPreferences();
-
ReactDOM.render(
<Root map={props} />,
document.getElementById('channel_view')
);
-}; \ No newline at end of file
+};
diff --git a/web/react/stores/channel_store.jsx b/web/react/stores/channel_store.jsx
index 93d996e0b..2337a573d 100644
--- a/web/react/stores/channel_store.jsx
+++ b/web/react/stores/channel_store.jsx
@@ -36,7 +36,7 @@ class ChannelStoreClass extends EventEmitter {
this.get = this.get.bind(this);
this.getMember = this.getMember.bind(this);
this.getByName = this.getByName.bind(this);
- this.pSetPostMode = this.pSetPostMode.bind(this);
+ this.setPostMode = this.setPostMode.bind(this);
this.getPostMode = this.getPostMode.bind(this);
this.setUnreadCount = this.setUnreadCount.bind(this);
this.setUnreadCounts = this.setUnreadCounts.bind(this);
@@ -95,7 +95,7 @@ class ChannelStoreClass extends EventEmitter {
this.removeListener(LEAVE_EVENT, callback);
}
findFirstBy(field, value) {
- var channels = this.pGetChannels();
+ var channels = this.getChannels();
for (var i = 0; i < channels.length; i++) {
if (channels[i][field] === value) {
return channels[i];
@@ -114,13 +114,13 @@ class ChannelStoreClass extends EventEmitter {
return this.findFirstBy('name', name);
}
getAll() {
- return this.pGetChannels();
+ return this.getChannels();
}
getAllMembers() {
- return this.pGetChannelMembers();
+ return this.getChannelMembers();
}
getMoreAll() {
- return this.pGetMoreChannels();
+ return this.getMoreChannels();
}
setCurrentId(id) {
this.currentId = id;
@@ -161,9 +161,9 @@ class ChannelStoreClass extends EventEmitter {
return null;
}
setChannelMember(member) {
- var members = this.pGetChannelMembers();
+ var members = this.getChannelMembers();
members[member.channel_id] = member;
- this.pStoreChannelMembers(members);
+ this.storeChannelMembers(members);
this.emitChange();
}
getCurrentExtraInfo() {
@@ -173,7 +173,7 @@ class ChannelStoreClass extends EventEmitter {
var extra = null;
if (channelId) {
- extra = this.pGetExtraInfos()[channelId];
+ extra = this.getExtraInfos()[channelId];
}
if (extra) {
@@ -186,7 +186,7 @@ class ChannelStoreClass extends EventEmitter {
return extra;
}
pStoreChannel(channel) {
- var channels = this.pGetChannels();
+ var channels = this.getChannels();
var found;
for (var i = 0; i < channels.length; i++) {
@@ -206,42 +206,42 @@ class ChannelStoreClass extends EventEmitter {
}
channels.sort(Utils.sortByDisplayName);
- this.pStoreChannels(channels);
+ this.storeChannels(channels);
}
- pStoreChannels(channels) {
+ storeChannels(channels) {
this.channels = channels;
}
- pGetChannels() {
+ getChannels() {
return this.channels;
}
pStoreChannelMember(channelMember) {
- var members = this.pGetChannelMembers();
+ var members = this.getChannelMembers();
members[channelMember.channel_id] = channelMember;
- this.pStoreChannelMembers(members);
+ this.storeChannelMembers(members);
}
- pStoreChannelMembers(channelMembers) {
+ storeChannelMembers(channelMembers) {
this.channelMembers = channelMembers;
}
- pGetChannelMembers() {
+ getChannelMembers() {
return this.channelMembers;
}
- pStoreMoreChannels(channels) {
+ storeMoreChannels(channels) {
this.moreChannels = channels;
}
- pGetMoreChannels() {
+ getMoreChannels() {
return this.moreChannels;
}
- pStoreExtraInfos(extraInfos) {
+ storeExtraInfos(extraInfos) {
this.extraInfos = extraInfos;
}
- pGetExtraInfos() {
+ getExtraInfos() {
return this.extraInfos;
}
isDefault(channel) {
return channel.name === Constants.DEFAULT_CHANNEL;
}
- pSetPostMode(mode) {
+ setPostMode(mode) {
this.postMode = mode;
}
@@ -292,21 +292,21 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
case ActionTypes.CLICK_CHANNEL:
ChannelStore.setCurrentId(action.id);
ChannelStore.resetCounts(action.id);
- ChannelStore.pSetPostMode(ChannelStore.POST_MODE_CHANNEL);
+ ChannelStore.setPostMode(ChannelStore.POST_MODE_CHANNEL);
ChannelStore.emitChange();
break;
case ActionTypes.RECIEVED_FOCUSED_POST: {
const post = action.post_list.posts[action.postId];
ChannelStore.setCurrentId(post.channel_id);
- ChannelStore.pSetPostMode(ChannelStore.POST_MODE_FOCUS);
+ ChannelStore.setPostMode(ChannelStore.POST_MODE_FOCUS);
ChannelStore.emitChange();
break;
}
case ActionTypes.RECIEVED_CHANNELS:
- ChannelStore.pStoreChannels(action.channels);
- ChannelStore.pStoreChannelMembers(action.members);
+ ChannelStore.storeChannels(action.channels);
+ ChannelStore.storeChannelMembers(action.members);
currentId = ChannelStore.getCurrentId();
if (currentId) {
ChannelStore.resetCounts(currentId);
@@ -329,14 +329,14 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
break;
case ActionTypes.RECIEVED_MORE_CHANNELS:
- ChannelStore.pStoreMoreChannels(action.channels);
+ ChannelStore.storeMoreChannels(action.channels);
ChannelStore.emitMoreChange();
break;
case ActionTypes.RECIEVED_CHANNEL_EXTRA_INFO:
- var extraInfos = ChannelStore.pGetExtraInfos();
+ var extraInfos = ChannelStore.getExtraInfos();
extraInfos[action.extra_info.id] = action.extra_info;
- ChannelStore.pStoreExtraInfos(extraInfos);
+ ChannelStore.storeExtraInfos(extraInfos);
ChannelStore.emitExtraInfoChange();
break;
diff --git a/web/react/stores/preference_store.jsx b/web/react/stores/preference_store.jsx
index 79eab4fe1..7ecaf0a95 100644
--- a/web/react/stores/preference_store.jsx
+++ b/web/react/stores/preference_store.jsx
@@ -133,6 +133,16 @@ class PreferenceStoreClass extends EventEmitter {
return preference;
}
+ setPreferences(newPreferences) {
+ const preferences = this.getAllPreferences();
+
+ for (const preference of newPreferences) {
+ preferences.set(getPreferenceKeyForModel(preference), preference);
+ }
+
+ this.setAllPreferences(preferences);
+ }
+
emitChange() {
this.emit(CHANGE_EVENT);
}
@@ -155,18 +165,11 @@ class PreferenceStoreClass extends EventEmitter {
this.emitChange();
break;
}
- case ActionTypes.RECIEVED_PREFERENCES: {
- const preferences = this.getAllPreferences();
-
- for (const preference of action.preferences) {
- preferences.set(getPreferenceKeyForModel(preference), preference);
- }
-
- this.setAllPreferences(preferences);
+ case ActionTypes.RECIEVED_PREFERENCES:
+ this.setPreferences(action.preferences);
this.emitChange();
break;
}
- }
}
}
diff --git a/web/templates/channel.html b/web/templates/channel.html
index dcc50115b..94d79a022 100644
--- a/web/templates/channel.html
+++ b/web/templates/channel.html
@@ -6,7 +6,7 @@
<body>
<div id="channel_view" class='channel-view'></div>
<script>
-window.setup_channel_page({{ .Props }}, {{ .Team }}, {{ .Channel }}, {{ .User }});
+ window.setup_channel_page({{ .Props }}, {{ .Team }}, {{ .Channel }});
$('body').tooltip( {selector: '[data-toggle=tooltip]'} );
var modals = $('.modal-body').not('.edit-modal-body');
if($(window).height() > 1200){
diff --git a/web/templates/claim_account.html b/web/templates/claim_account.html
index 6c9f36fa7..bcf63fd95 100644
--- a/web/templates/claim_account.html
+++ b/web/templates/claim_account.html
@@ -5,8 +5,22 @@
<body class="white">
<div class="container-fluid">
<div class="inner__wrap">
- <div class="row content" id="claim"></div>
- </div>
+ <div class="row content">
+ <div class="signup-header">
+ <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a>
+ </div>
+ <div class="col-sm-12">
+ <div class="signup-team__container">
+ <img class="signup-team-logo" src="/static/images/logo.png" />
+ <div id="claim"></div>
+ </div>
+ </div>
+ <div class="footer-push"></div>
+ </div>
+ <div class="row footer">
+ {{template "footer" . }}
+ </div>
+ <div>
</div>
<script>
window.setup_claim_account_page({{ .Props }});
diff --git a/web/templates/docs.html b/web/templates/docs.html
index 0e0f51648..1a20580fb 100644
--- a/web/templates/docs.html
+++ b/web/templates/docs.html
@@ -6,6 +6,9 @@
<div class="container-fluid">
<div class="inner__wrap">
<div class="row content">
+ <div class="signup-header">
+ <a href="/">{{ .ClientCfg.SiteName }}</a>
+ </div>
<div class="col-sm-12">
<div class="docs__page" id="docs"></div>
</div>
diff --git a/web/templates/find_team.html b/web/templates/find_team.html
index 9acf3ac64..d32ea0dc8 100644
--- a/web/templates/find_team.html
+++ b/web/templates/find_team.html
@@ -6,6 +6,9 @@
<div class="container-fluid">
<div class="inner__wrap">
<div class="row content">
+ <div class="signup-header">
+ <a href="/">{{ .ClientCfg.SiteName }}</a>
+ </div>
<div class="col-sm-12">
<div class="signup-team__container">
<img class="signup-team-logo" src="/static/images/logo.png" />
diff --git a/web/templates/head.html b/web/templates/head.html
index cf1d37b53..257877376 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -74,6 +74,11 @@
window.mm_user = {{ .User }};
window.mm_channel = {{ .Channel }};
window.mm_locale = {{ .Locale }};
+ window.mm_preferences = {{ .Preferences }};
+
+ $(function() {
+ PreferenceStore.setPreferences(window.mm_preferences);
+ });
if ({{.SessionTokenIndex}} >= 0) {
window.mm_session_token_index = {{.SessionTokenIndex}};
diff --git a/web/templates/login.html b/web/templates/login.html
index f6a551220..be5e6bf4f 100644
--- a/web/templates/login.html
+++ b/web/templates/login.html
@@ -7,7 +7,7 @@
<div class="inner__wrap">
<div class="row content">
<div class="signup-header">
- {{.Props.TeamDisplayName}}
+ <a href="/">{{ .ClientCfg.SiteName }}</a>
</div>
<div class="col-sm-12">
<div id="login"></div>
diff --git a/web/templates/password_reset.html b/web/templates/password_reset.html
index 7f6335c92..df82285ef 100644
--- a/web/templates/password_reset.html
+++ b/web/templates/password_reset.html
@@ -5,7 +5,21 @@
<body class="white">
<div class="container-fluid">
<div class="inner__wrap">
- <div class="row content" id="reset"></div>
+ <div class="row content">
+ <div class="signup-header">
+ <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a>
+ </div>
+ <div class="col-sm-12">
+ <div class="signup-team__container">
+ <img class="signup-team-logo" src="/static/images/logo.png" />
+ <div id="reset"></div>
+ </div>
+ </div>
+ <div class="footer-push"></div>
+ </div>
+ <div class="row footer">
+ {{template "footer" . }}
+ </div>
</div>
</div>
<script>
diff --git a/web/templates/verify.html b/web/templates/verify.html
index a49ba7930..bab329c7d 100644
--- a/web/templates/verify.html
+++ b/web/templates/verify.html
@@ -6,7 +6,16 @@
<div class="container-fluid">
<div class="inner__wrap">
<div class="row content">
- <div id="verify"></div>
+ <div class="signup-header">
+ <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a>
+ </div>
+ <div class="col-sm-12">
+ <div class="signup-team__container">
+ <img class="signup-team-logo" src="/static/images/logo.png" />
+ <div id="verify"></div>
+ </div>
+ </div>
+ <div class="footer-push"></div>
</div>
<div class="row footer">
{{template "footer" . }}
diff --git a/web/templates/welcome.html b/web/templates/welcome.html
deleted file mode 100644
index 15c072226..000000000
--- a/web/templates/welcome.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{{define "welcome"}}
-<!DOCTYPE html>
-<html>
-{{template "head" . }}
-<body>
- <div class="container-fluid">
- <div class="inner__wrap">
- <div class="row header">
- <div id="navbar"></div>
- </div>
- <div class="row main">
- <div class="app__content">
- <div class="welcome-info">
- <h1>Welcome to {{ .ClientCfg.SiteName }}!</h1>
- <p>
- You do not appear to be part of any teams. Please contact your
- administrator to have him send you an invitation to a private team.
- Or you can start a new private team.
- </p>
- <div class="alert alert-warning">
- If you where invited to a team that you do not see you must
- confirm your email address first before gaining access to the
- team.
- </div>
- <div id="new_channel">
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <script>
- window.setup_welcome_page();
- </script>
-</body>
-</html>
-{{end}}
diff --git a/web/web.go b/web/web.go
index 95d6024f5..36349dd5e 100644
--- a/web/web.go
+++ b/web/web.go
@@ -518,6 +518,7 @@ func checkSessionSwitch(c *api.Context, w http.ResponseWriter, r *http.Request,
func doLoadChannel(c *api.Context, w http.ResponseWriter, r *http.Request, team *model.Team, channel *model.Channel, postid string) {
userChan := api.Srv.Store.User().Get(c.Session.UserId)
+ prefChan := api.Srv.Store.Preference().GetAll(c.Session.UserId)
var user *model.User
if ur := <-userChan; ur.Err != nil {
@@ -529,6 +530,13 @@ func doLoadChannel(c *api.Context, w http.ResponseWriter, r *http.Request, team
user = ur.Data.(*model.User)
}
+ var preferences model.Preferences
+ if result := <-prefChan; result.Err != nil {
+ l4g.Error("Error in getting preferences for id=%v", c.Session.UserId)
+ } else {
+ preferences = result.Data.(model.Preferences)
+ }
+
page := NewHtmlTemplatePage("channel", "", c.Locale)
page.Props["Title"] = channel.DisplayName + " - " + team.DisplayName + " " + page.ClientCfg["SiteName"]
page.Props["TeamDisplayName"] = team.DisplayName
@@ -538,6 +546,7 @@ func doLoadChannel(c *api.Context, w http.ResponseWriter, r *http.Request, team
page.Team = team
page.User = user
page.Channel = channel
+ page.Preferences = &preferences
page.Render(c, w)
}