Этот коммит содержится в:
=Corey Hulen
2016-03-16 18:13:16 -07:00
родитель e101b2cf7c cba59d4eb6
Коммит b9d5b4e5dc
4983 изменённых файлов: 16487 добавлений и 1611263 удалений

192
webapp/stores/admin_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,192 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import BrowserStore from 'stores/browser_store.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const LOG_CHANGE_EVENT = 'log_change';
const SERVER_AUDIT_CHANGE_EVENT = 'server_audit_change';
const CONFIG_CHANGE_EVENT = 'config_change';
const ALL_TEAMS_EVENT = 'all_team_change';
const SERVER_COMPLIANCE_REPORT_CHANGE_EVENT = 'server_compliance_reports_change';
class AdminStoreClass extends EventEmitter {
constructor() {
super();
this.logs = null;
this.audits = null;
this.config = null;
this.teams = null;
this.complianceReports = null;
this.emitLogChange = this.emitLogChange.bind(this);
this.addLogChangeListener = this.addLogChangeListener.bind(this);
this.removeLogChangeListener = this.removeLogChangeListener.bind(this);
this.emitAuditChange = this.emitAuditChange.bind(this);
this.addAuditChangeListener = this.addAuditChangeListener.bind(this);
this.removeAuditChangeListener = this.removeAuditChangeListener.bind(this);
this.emitComplianceReportsChange = this.emitComplianceReportsChange.bind(this);
this.addComplianceReportsChangeListener = this.addComplianceReportsChangeListener.bind(this);
this.removeComplianceReportsChangeListener = this.removeComplianceReportsChangeListener.bind(this);
this.emitConfigChange = this.emitConfigChange.bind(this);
this.addConfigChangeListener = this.addConfigChangeListener.bind(this);
this.removeConfigChangeListener = this.removeConfigChangeListener.bind(this);
this.emitAllTeamsChange = this.emitAllTeamsChange.bind(this);
this.addAllTeamsChangeListener = this.addAllTeamsChangeListener.bind(this);
this.removeAllTeamsChangeListener = this.removeAllTeamsChangeListener.bind(this);
}
emitLogChange() {
this.emit(LOG_CHANGE_EVENT);
}
addLogChangeListener(callback) {
this.on(LOG_CHANGE_EVENT, callback);
}
removeLogChangeListener(callback) {
this.removeListener(LOG_CHANGE_EVENT, callback);
}
emitAuditChange() {
this.emit(SERVER_AUDIT_CHANGE_EVENT);
}
addAuditChangeListener(callback) {
this.on(SERVER_AUDIT_CHANGE_EVENT, callback);
}
removeAuditChangeListener(callback) {
this.removeListener(SERVER_AUDIT_CHANGE_EVENT, callback);
}
emitComplianceReportsChange() {
this.emit(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT);
}
addComplianceReportsChangeListener(callback) {
this.on(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT, callback);
}
removeComplianceReportsChangeListener(callback) {
this.removeListener(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT, callback);
}
emitConfigChange() {
this.emit(CONFIG_CHANGE_EVENT);
}
addConfigChangeListener(callback) {
this.on(CONFIG_CHANGE_EVENT, callback);
}
removeConfigChangeListener(callback) {
this.removeListener(CONFIG_CHANGE_EVENT, callback);
}
emitAllTeamsChange() {
this.emit(ALL_TEAMS_EVENT);
}
addAllTeamsChangeListener(callback) {
this.on(ALL_TEAMS_EVENT, callback);
}
removeAllTeamsChangeListener(callback) {
this.removeListener(ALL_TEAMS_EVENT, callback);
}
getLogs() {
return this.logs;
}
saveLogs(logs) {
this.logs = logs;
}
getAudits() {
return this.audits;
}
saveAudits(audits) {
this.audits = audits;
}
getComplianceReports() {
return this.complianceReports;
}
saveComplianceReports(complianceReports) {
this.complianceReports = complianceReports;
}
getConfig() {
return this.config;
}
saveConfig(config) {
this.config = config;
}
getAllTeams() {
return this.teams;
}
saveAllTeams(teams) {
this.teams = teams;
}
getSelectedTeams() {
const result = BrowserStore.getItem('seleted_teams');
if (!result) {
return {};
}
return result;
}
saveSelectedTeams(teams) {
BrowserStore.setItem('seleted_teams', teams);
}
}
var AdminStore = new AdminStoreClass();
AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_LOGS:
AdminStore.saveLogs(action.logs);
AdminStore.emitLogChange();
break;
case ActionTypes.RECEIVED_SERVER_AUDITS:
AdminStore.saveAudits(action.audits);
AdminStore.emitAuditChange();
break;
case ActionTypes.RECEIVED_SERVER_COMPLIANCE_REPORTS:
AdminStore.saveComplianceReports(action.complianceReports);
AdminStore.emitComplianceReportsChange();
break;
case ActionTypes.RECEIVED_CONFIG:
AdminStore.saveConfig(action.config);
AdminStore.emitConfigChange();
break;
case ActionTypes.RECEIVED_ALL_TEAMS:
AdminStore.saveAllTeams(action.teams);
AdminStore.emitAllTeamsChange();
break;
default:
}
});
export default AdminStore;

85
webapp/stores/analytics_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,85 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
class AnalyticsStoreClass extends EventEmitter {
constructor() {
super();
this.systemStats = {};
this.teamStats = {};
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
getAllSystem() {
return JSON.parse(JSON.stringify(this.systemStats));
}
getAllTeam(id) {
if (id in this.teamStats) {
return JSON.parse(JSON.stringify(this.teamStats[id]));
}
return {};
}
storeSystemStats(newStats) {
for (const stat in newStats) {
if (!newStats.hasOwnProperty(stat)) {
continue;
}
this.systemStats[stat] = newStats[stat];
}
}
storeTeamStats(id, newStats) {
if (!(id in this.teamStats)) {
this.teamStats[id] = {};
}
for (const stat in newStats) {
if (!newStats.hasOwnProperty(stat)) {
continue;
}
this.teamStats[id][stat] = newStats[stat];
}
}
}
var AnalyticsStore = new AnalyticsStoreClass();
AnalyticsStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_ANALYTICS:
if (action.teamId == null) {
AnalyticsStore.storeSystemStats(action.stats);
} else {
AnalyticsStore.storeTeamStats(action.teamId, action.stats);
}
AnalyticsStore.emitChange();
break;
default:
}
});
export default AnalyticsStore;

225
webapp/stores/browser_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,225 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {generateId} from 'utils/utils.jsx';
function getPrefix() {
if (global.window.mm_current_user_id) {
return global.window.mm_current_user_id + '_';
}
return 'unknown_';
}
class BrowserStoreClass {
constructor() {
this.getItem = this.getItem.bind(this);
this.setItem = this.setItem.bind(this);
this.removeItem = this.removeItem.bind(this);
this.setGlobalItem = this.setGlobalItem.bind(this);
this.getGlobalItem = this.getGlobalItem.bind(this);
this.removeGlobalItem = this.removeGlobalItem.bind(this);
this.actionOnItemsWithPrefix = this.actionOnItemsWithPrefix.bind(this);
this.actionOnGlobalItemsWithPrefix = this.actionOnGlobalItemsWithPrefix.bind(this);
this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this);
this.getLastServerVersion = this.getLastServerVersion.bind(this);
this.setLastServerVersion = this.setLastServerVersion.bind(this);
this.clear = this.clear.bind(this);
this.clearAll = this.clearAll.bind(this);
this.checkedLocalStorageSupported = '';
this.signalLogout = this.signalLogout.bind(this);
this.isSignallingLogout = this.isSignallingLogout.bind(this);
this.signalLogin = this.signalLogin.bind(this);
this.isSignallingLogin = this.isSignallingLogin.bind(this);
}
checkVersion() {
var currentVersion = sessionStorage.getItem('storage_version');
if (currentVersion !== global.window.mm_config.Version) {
sessionStorage.clear();
try {
sessionStorage.setItem('storage_version', global.window.mm_config.Version);
} catch (e) {
// Do nothing
}
}
}
getItem(name, defaultValue) {
var result = null;
try {
result = JSON.parse(sessionStorage.getItem(getPrefix() + name));
} catch (err) {
result = null;
}
if (result === null && typeof defaultValue !== 'undefined') {
result = defaultValue;
}
return result;
}
setItem(name, value) {
sessionStorage.setItem(getPrefix() + name, JSON.stringify(value));
}
removeItem(name) {
sessionStorage.removeItem(getPrefix() + name);
}
setGlobalItem(name, value) {
try {
if (this.isLocalStorageSupported()) {
localStorage.setItem(getPrefix() + name, JSON.stringify(value));
} else {
sessionStorage.setItem(getPrefix() + name, JSON.stringify(value));
}
} catch (err) {
console.log('An error occurred while setting local storage, clearing all props'); //eslint-disable-line no-console
localStorage.clear();
sessionStorage.clear();
window.location.reload(true);
}
}
getGlobalItem(name, defaultValue) {
var result = null;
try {
if (this.isLocalStorageSupported()) {
result = JSON.parse(localStorage.getItem(getPrefix() + name));
} else {
result = JSON.parse(sessionStorage.getItem(getPrefix() + name));
}
} catch (err) {
result = null;
}
if (result === null && typeof defaultValue !== 'undefined') {
result = defaultValue;
}
return result;
}
removeGlobalItem(name) {
if (this.isLocalStorageSupported()) {
localStorage.removeItem(getPrefix() + name);
} else {
sessionStorage.removeItem(getPrefix() + name);
}
}
getLastServerVersion() {
return sessionStorage.getItem('last_server_version');
}
setLastServerVersion(version) {
sessionStorage.setItem('last_server_version', version);
}
signalLogout() {
if (this.isLocalStorageSupported()) {
// PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11
const logoutId = generateId();
sessionStorage.setItem('__logout__', logoutId);
localStorage.setItem('__logout__', logoutId);
localStorage.removeItem('__logout__');
}
}
isSignallingLogout(logoutId) {
return logoutId === sessionStorage.getItem('__logout__');
}
signalLogin() {
if (this.isLocalStorageSupported()) {
// PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11
const loginId = generateId();
sessionStorage.setItem('__login__', loginId);
localStorage.setItem('__login__', loginId);
localStorage.removeItem('__login__');
}
}
isSignallingLogin(loginId) {
return loginId === sessionStorage.getItem('__login__');
}
/**
* Preforms the given action on each item that has the given prefix
* Signature for action is action(key, value)
*/
actionOnGlobalItemsWithPrefix(prefix, action) {
var globalPrefix = getPrefix();
var globalPrefixiLen = globalPrefix.length;
var storage = sessionStorage;
if (this.isLocalStorageSupported()) {
storage = localStorage;
}
for (var key in storage) {
if (key.lastIndexOf(globalPrefix + prefix, 0) === 0) {
var userkey = key.substring(globalPrefixiLen);
action(userkey, this.getGlobalItem(key));
}
}
}
actionOnItemsWithPrefix(prefix, action) {
var globalPrefix = getPrefix();
var globalPrefixiLen = globalPrefix.length;
for (var key in sessionStorage) {
if (key.lastIndexOf(globalPrefix + prefix, 0) === 0) {
var userkey = key.substring(globalPrefixiLen);
action(userkey, this.getGlobalItem(key));
}
}
}
clear() {
// don't clear the logout id so IE11 can tell which tab sent a logout request
const logoutId = sessionStorage.getItem('__logout__');
sessionStorage.clear();
if (logoutId) {
sessionStorage.setItem('__logout__', logoutId);
}
}
clearAll() {
sessionStorage.clear();
localStorage.clear();
}
isLocalStorageSupported() {
if (this.checkedLocalStorageSupported !== '') {
return this.checkedLocalStorageSupported;
}
try {
sessionStorage.setItem('__testSession__', '1');
sessionStorage.removeItem('__testSession__');
localStorage.setItem('__testLocal__', '1');
if (localStorage.getItem('__testLocal__') !== '1') {
this.checkedLocalStorageSupported = false;
}
localStorage.removeItem('__testLocal__', '1');
this.checkedLocalStorageSupported = true;
} catch (e) {
this.checkedLocalStorageSupported = false;
}
return this.checkedLocalStorageSupported;
}
}
var BrowserStore = new BrowserStoreClass();
export default BrowserStore;
window.BrowserStore = BrowserStore;

352
webapp/stores/channel_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,352 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
var Utils;
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const NotificationPrefs = Constants.NotificationPrefs;
const CHANGE_EVENT = 'change';
const LEAVE_EVENT = 'leave';
const MORE_CHANGE_EVENT = 'change';
const EXTRA_INFO_EVENT = 'extra_info';
class ChannelStoreClass extends EventEmitter {
constructor(props) {
super(props);
this.setMaxListeners(15);
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.emitMoreChange = this.emitMoreChange.bind(this);
this.addMoreChangeListener = this.addMoreChangeListener.bind(this);
this.removeMoreChangeListener = this.removeMoreChangeListener.bind(this);
this.emitExtraInfoChange = this.emitExtraInfoChange.bind(this);
this.addExtraInfoChangeListener = this.addExtraInfoChangeListener.bind(this);
this.removeExtraInfoChangeListener = this.removeExtraInfoChangeListener.bind(this);
this.emitLeave = this.emitLeave.bind(this);
this.addLeaveListener = this.addLeaveListener.bind(this);
this.removeLeaveListener = this.removeLeaveListener.bind(this);
this.findFirstBy = this.findFirstBy.bind(this);
this.get = this.get.bind(this);
this.getMember = this.getMember.bind(this);
this.getByName = this.getByName.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);
this.getUnreadCount = this.getUnreadCount.bind(this);
this.getUnreadCounts = this.getUnreadCounts.bind(this);
this.currentId = null;
this.postMode = this.POST_MODE_CHANNEL;
this.channels = [];
this.channelMembers = {};
this.moreChannels = {};
this.moreChannels.loading = true;
this.extraInfos = {};
this.unreadCounts = {};
}
get POST_MODE_CHANNEL() {
return 1;
}
get POST_MODE_FOCUS() {
return 2;
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitMoreChange() {
this.emit(MORE_CHANGE_EVENT);
}
addMoreChangeListener(callback) {
this.on(MORE_CHANGE_EVENT, callback);
}
removeMoreChangeListener(callback) {
this.removeListener(MORE_CHANGE_EVENT, callback);
}
emitExtraInfoChange() {
this.emit(EXTRA_INFO_EVENT);
}
addExtraInfoChangeListener(callback) {
this.on(EXTRA_INFO_EVENT, callback);
}
removeExtraInfoChangeListener(callback) {
this.removeListener(EXTRA_INFO_EVENT, callback);
}
emitLeave(id) {
this.emit(LEAVE_EVENT, id);
}
addLeaveListener(callback) {
this.on(LEAVE_EVENT, callback);
}
removeLeaveListener(callback) {
this.removeListener(LEAVE_EVENT, callback);
}
findFirstBy(field, value) {
var channels = this.getChannels();
for (var i = 0; i < channels.length; i++) {
if (channels[i][field] === value) {
return channels[i];
}
}
return null;
}
get(id) {
return this.findFirstBy('id', id);
}
getMember(id) {
return this.getAllMembers()[id];
}
getByName(name) {
return this.findFirstBy('name', name);
}
getAll() {
return this.getChannels();
}
getAllMembers() {
return this.getChannelMembers();
}
getMoreAll() {
return this.getMoreChannels();
}
setCurrentId(id) {
this.currentId = id;
}
resetCounts(id) {
const cm = this.channelMembers;
for (var cmid in cm) {
if (cm[cmid].channel_id === id) {
var c = this.get(id);
if (c) {
cm[cmid].msg_count = this.get(id).total_msg_count;
cm[cmid].mention_count = 0;
this.setUnreadCount(id);
}
break;
}
}
}
getCurrentId() {
return this.currentId;
}
getCurrent() {
var currentId = this.getCurrentId();
if (currentId) {
return this.get(currentId);
}
return null;
}
getCurrentMember() {
var currentId = this.getCurrentId();
if (currentId) {
return this.getAllMembers()[currentId];
}
return null;
}
setChannelMember(member) {
var members = this.getChannelMembers();
members[member.channel_id] = member;
this.storeChannelMembers(members);
this.emitChange();
}
getCurrentExtraInfo() {
return this.getExtraInfo(this.getCurrentId());
}
getExtraInfo(channelId) {
var extra = null;
if (channelId) {
extra = this.getExtraInfos()[channelId];
}
if (extra) {
// create a defensive copy
extra = JSON.parse(JSON.stringify(extra));
} else {
extra = {members: []};
}
return extra;
}
pStoreChannel(channel) {
var channels = this.getChannels();
var found;
for (var i = 0; i < channels.length; i++) {
if (channels[i].id === channel.id) {
channels[i] = channel;
found = true;
break;
}
}
if (!found) {
channels.push(channel);
}
if (!Utils) {
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
}
channels.sort(Utils.sortByDisplayName);
this.storeChannels(channels);
}
storeChannels(channels) {
this.channels = channels;
}
getChannels() {
return this.channels;
}
pStoreChannelMember(channelMember) {
var members = this.getChannelMembers();
members[channelMember.channel_id] = channelMember;
this.storeChannelMembers(members);
}
storeChannelMembers(channelMembers) {
this.channelMembers = channelMembers;
}
getChannelMembers() {
return this.channelMembers;
}
storeMoreChannels(channels) {
this.moreChannels = channels;
}
getMoreChannels() {
return this.moreChannels;
}
storeExtraInfos(extraInfos) {
this.extraInfos = extraInfos;
}
getExtraInfos() {
return this.extraInfos;
}
isDefault(channel) {
return channel.name === Constants.DEFAULT_CHANNEL;
}
setPostMode(mode) {
this.postMode = mode;
}
getPostMode() {
return this.postMode;
}
setUnreadCount(id) {
const ch = this.get(id);
const chMember = this.getMember(id);
let chMentionCount = chMember.mention_count;
let chUnreadCount = ch.total_msg_count - chMember.msg_count - chMentionCount;
if (ch.type === 'D') {
chMentionCount = chUnreadCount;
chUnreadCount = 0;
} else if (chMember.notify_props && chMember.notify_props.mark_unread === NotificationPrefs.MENTION) {
chUnreadCount = 0;
}
this.unreadCounts[id] = {msgs: chUnreadCount, mentions: chMentionCount};
}
setUnreadCounts() {
const channels = this.getAll();
channels.forEach((ch) => {
this.setUnreadCount(ch.id);
});
}
getUnreadCount(id) {
return this.unreadCounts[id] || {msgs: 0, mentions: 0};
}
getUnreadCounts() {
return this.unreadCounts;
}
}
var ChannelStore = new ChannelStoreClass();
ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
var currentId;
switch (action.type) {
case ActionTypes.CLICK_CHANNEL:
ChannelStore.setCurrentId(action.id);
ChannelStore.resetCounts(action.id);
ChannelStore.setPostMode(ChannelStore.POST_MODE_CHANNEL);
ChannelStore.emitChange();
break;
case ActionTypes.RECEIVED_FOCUSED_POST: {
const post = action.post_list.posts[action.postId];
ChannelStore.setCurrentId(post.channel_id);
ChannelStore.setPostMode(ChannelStore.POST_MODE_FOCUS);
ChannelStore.emitChange();
break;
}
case ActionTypes.RECEIVED_CHANNELS:
ChannelStore.storeChannels(action.channels);
ChannelStore.storeChannelMembers(action.members);
currentId = ChannelStore.getCurrentId();
if (currentId && window.isActive) {
ChannelStore.resetCounts(currentId);
}
ChannelStore.setUnreadCounts();
ChannelStore.emitChange();
break;
case ActionTypes.RECEIVED_CHANNEL:
ChannelStore.pStoreChannel(action.channel);
if (action.member) {
ChannelStore.pStoreChannelMember(action.member);
}
currentId = ChannelStore.getCurrentId();
if (currentId && window.isActive) {
ChannelStore.resetCounts(currentId);
}
ChannelStore.setUnreadCount(action.channel.id);
ChannelStore.emitChange();
break;
case ActionTypes.RECEIVED_MORE_CHANNELS:
ChannelStore.storeMoreChannels(action.channels);
ChannelStore.emitMoreChange();
break;
case ActionTypes.RECEIVED_CHANNEL_EXTRA_INFO:
var extraInfos = ChannelStore.getExtraInfos();
extraInfos[action.extra_info.id] = action.extra_info;
ChannelStore.storeExtraInfos(extraInfos);
ChannelStore.emitExtraInfoChange();
break;
case ActionTypes.LEAVE_CHANNEL:
ChannelStore.emitLeave(action.id);
break;
default:
break;
}
});
export default ChannelStore;

80
webapp/stores/error_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,80 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
import BrowserStore from 'stores/browser_store.jsx';
const CHANGE_EVENT = 'change';
class ErrorStoreClass extends EventEmitter {
constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.getLastError = this.getLastError.bind(this);
this.storeLastError = this.storeLastError.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
getLastError() {
return BrowserStore.getItem('last_error');
}
storeLastError(error) {
BrowserStore.setItem('last_error', error);
}
getConnectionErrorCount() {
var count = BrowserStore.getItem('last_error_conn');
if (count == null) {
return 0;
}
return count;
}
setConnectionErrorCount(count) {
BrowserStore.setItem('last_error_conn', count);
}
clearLastError() {
BrowserStore.removeItem('last_error');
BrowserStore.removeItem('last_error_conn');
}
}
var ErrorStore = new ErrorStoreClass();
ErrorStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_ERROR:
ErrorStore.storeLastError(action.err);
ErrorStore.emitChange();
break;
default:
}
});
export default ErrorStore;
window.ErrorStore = ErrorStore;

60
webapp/stores/file_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,60 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import Constants from 'utils/constants.jsx';
import EventEmitter from 'events';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'changed';
class FileStore extends EventEmitter {
constructor() {
super();
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.emitChange = this.emitChange.bind(this);
this.handleEventPayload = this.handleEventPayload.bind(this);
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
this.fileInfo = new Map();
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitChange(filename) {
this.emit(CHANGE_EVENT, filename);
}
hasInfo(filename) {
return this.fileInfo.has(filename);
}
getInfo(filename) {
return this.fileInfo.get(filename);
}
setInfo(filename, info) {
this.fileInfo.set(filename, info);
}
handleEventPayload(payload) {
const action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_FILE_INFO:
this.setInfo(action.filename, action.info);
this.emitChange(action.filename);
break;
}
}
}
export default new FileStore();

60
webapp/stores/localization_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,60 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
class LocalizationStoreClass extends EventEmitter {
constructor() {
super();
this.currentLocale = 'en';
this.currentTranslations = null;
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
setCurrentLocale(locale, translations) {
this.currentLocale = locale;
this.currentTranslations = translations;
}
getLocale() {
return this.currentLocale;
}
getTranslations() {
return this.currentTranslations;
}
}
var LocalizationStore = new LocalizationStoreClass();
LocalizationStore.setMaxListeners(0);
LocalizationStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_LOCALE:
LocalizationStore.setCurrentLocale(action.locale, action.translations);
LocalizationStore.emitChange();
break;
default:
}
});
export default LocalizationStore;

47
webapp/stores/modal_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,47 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
class ModalStoreClass extends EventEmitter {
constructor() {
super();
this.addModalListener = this.addModalListener.bind(this);
this.removeModalListener = this.removeModalListener.bind(this);
this.handleEventPayload = this.handleEventPayload.bind(this);
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
}
addModalListener(action, callback) {
this.on(action, callback);
}
removeModalListener(action, callback) {
this.removeListener(action, callback);
}
handleEventPayload(payload) {
// toggle event handlers should accept a boolean show/hide value and can accept a map of arguments
const {type, value, ...args} = payload.action; //eslint-disable-line no-use-before-define
switch (type) {
case ActionTypes.TOGGLE_IMPORT_THEME_MODAL:
case ActionTypes.TOGGLE_INVITE_MEMBER_MODAL:
case ActionTypes.TOGGLE_DELETE_POST_MODAL:
case ActionTypes.TOGGLE_GET_POST_LINK_MODAL:
case ActionTypes.TOGGLE_GET_TEAM_INVITE_LINK_MODAL:
case ActionTypes.TOGGLE_REGISTER_APP_MODAL:
this.emit(type, value, args);
break;
}
}
}
const ModalStore = new ModalStoreClass();
export default ModalStore;

610
webapp/stores/post_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,610 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import ChannelStore from 'stores/channel_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import UserStore from 'stores/user_store.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
const FOCUSED_POST_CHANGE = 'focused_post_change';
const EDIT_POST_EVENT = 'edit_post';
const POSTS_VIEW_JUMP_EVENT = 'post_list_jump';
const SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
class PostStoreClass extends EventEmitter {
constructor() {
super();
this.selectedPostId = null;
this.postsInfo = {};
this.currentFocusedPostId = null;
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitPostFocused() {
this.emit(FOCUSED_POST_CHANGE);
}
addPostFocusedListener(callback) {
this.on(FOCUSED_POST_CHANGE, callback);
}
removePostFocusedListener(callback) {
this.removeListener(FOCUSED_POST_CHANGE, callback);
}
emitEditPost(post) {
this.emit(EDIT_POST_EVENT, post);
}
addEditPostListener(callback) {
this.on(EDIT_POST_EVENT, callback);
}
removeEditPostListner(callback) {
this.removeListener(EDIT_POST_EVENT, callback);
}
emitPostsViewJump(type, post) {
this.emit(POSTS_VIEW_JUMP_EVENT, type, post);
}
addPostsViewJumpListener(callback) {
this.on(POSTS_VIEW_JUMP_EVENT, callback);
}
removePostsViewJumpListener(callback) {
this.removeListener(POSTS_VIEW_JUMP_EVENT, callback);
}
jumpPostsViewToBottom() {
this.emitPostsViewJump(Constants.PostsViewJumpTypes.BOTTOM, null);
}
jumpPostsViewToPost(post) {
this.emitPostsViewJump(Constants.PostsViewJumpTypes.POST, post);
}
jumpPostsViewSidebarOpen() {
this.emitPostsViewJump(Constants.PostsViewJumpTypes.SIDEBAR_OPEN, null);
}
// All this does is makes sure the postsInfo is not null for the specified channel
makePostsInfo(id) {
if (!this.postsInfo.hasOwnProperty(id)) {
this.postsInfo[id] = {};
}
}
getPost(channelId, postId) {
const posts = this.postsInfo[channelId].postList;
let post = null;
if (posts.posts.hasOwnProperty(postId)) {
post = Object.assign({}, posts.posts[postId]);
}
return post;
}
getAllPosts(id) {
if (this.postsInfo.hasOwnProperty(id)) {
return Object.assign({}, this.postsInfo[id].postList);
}
return null;
}
getEarliestPost(id) {
if (this.postsInfo.hasOwnProperty(id)) {
return this.postsInfo[id].postList.posts[this.postsInfo[id].postList.order[this.postsInfo[id].postList.order.length - 1]];
}
return null;
}
getLatestPost(id) {
if (this.postsInfo.hasOwnProperty(id)) {
return this.postsInfo[id].postList.posts[this.postsInfo[id].postList.order[0]];
}
return null;
}
getVisiblePosts(id) {
if (this.postsInfo.hasOwnProperty(id) && this.postsInfo[id].hasOwnProperty('postList')) {
const postList = JSON.parse(JSON.stringify(this.postsInfo[id].postList));
// Only limit visibility if we are not focused on a post
if (this.currentFocusedPostId === null) {
postList.order = postList.order.slice(0, this.postsInfo[id].endVisible);
}
// Add pending posts
if (this.postsInfo[id].hasOwnProperty('pendingPosts')) {
Object.assign(postList.posts, this.postsInfo[id].pendingPosts.posts);
postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order);
}
return postList;
}
return null;
}
getVisibilityAtTop(id) {
if (this.postsInfo.hasOwnProperty(id)) {
return this.postsInfo[id].atTop && this.postsInfo[id].endVisible >= this.postsInfo[id].postList.order.length;
}
return false;
}
getVisibilityAtBottom(id) {
if (this.postsInfo.hasOwnProperty(id)) {
return this.postsInfo[id].atBottom;
}
return false;
}
// Returns true if posts need to be fetched
requestVisibilityIncrease(id, ammount) {
const endVisible = this.postsInfo[id].endVisible;
const postList = this.postsInfo[id].postList;
if (this.getVisibilityAtTop(id)) {
return false;
}
this.postsInfo[id].endVisible += ammount;
this.emitChange();
return endVisible + ammount > postList.order.length;
}
getFocusedPostId() {
return this.currentFocusedPostId;
}
storePosts(id, newPosts) {
if (isPostListNull(newPosts)) {
return;
}
const combinedPosts = makePostListNonNull(this.getAllPosts(id));
for (const pid in newPosts.posts) {
if (newPosts.posts.hasOwnProperty(pid)) {
const np = newPosts.posts[pid];
if (np.delete_at === 0) {
combinedPosts.posts[pid] = np;
if (combinedPosts.order.indexOf(pid) === -1 && newPosts.order.indexOf(pid) !== -1) {
combinedPosts.order.push(pid);
}
}
}
}
combinedPosts.order.sort((a, b) => {
if (combinedPosts.posts[a].create_at > combinedPosts.posts[b].create_at) {
return -1;
}
if (combinedPosts.posts[a].create_at < combinedPosts.posts[b].create_at) {
return 1;
}
return 0;
});
this.makePostsInfo(id);
this.postsInfo[id].postList = combinedPosts;
}
storePost(post) {
const postList = makePostListNonNull(this.getAllPosts(post.channel_id));
if (post.pending_post_id !== '') {
this.removePendingPost(post.channel_id, post.pending_post_id);
}
post.pending_post_id = '';
postList.posts[post.id] = post;
if (postList.order.indexOf(post.id) === -1) {
postList.order.unshift(post.id);
}
this.makePostsInfo(post.channel_id);
this.postsInfo[post.channel_id].postList = postList;
}
storeFocusedPost(postId, postList) {
const focusedPost = postList.posts[postId];
if (!focusedPost) {
return;
}
this.currentFocusedPostId = postId;
this.storePosts(postId, postList);
}
checkBounds(id, numRequested, postList, before) {
if (numRequested > postList.order.length) {
if (before) {
this.postsInfo[id].atTop = true;
} else {
this.postsInfo[id].atBottom = true;
}
}
}
clearFocusedPost() {
if (this.currentFocusedPostId != null) {
Reflect.deleteProperty(this.postsInfo, this.currentFocusedPostId);
this.currentFocusedPostId = null;
}
}
clearChannelVisibility(id, atBottom) {
this.makePostsInfo(id);
this.postsInfo[id].endVisible = Constants.POST_CHUNK_SIZE;
this.postsInfo[id].atTop = false;
this.postsInfo[id].atBottom = atBottom;
}
deletePost(post) {
const postInfo = this.postsInfo[post.channel_id];
if (!postInfo) {
// the post that has been deleted is in a channel that we haven't seen so just ignore it
return;
}
const postList = this.postsInfo[post.channel_id].postList;
if (isPostListNull(postList)) {
return;
}
if (post.id in postList.posts) {
// make sure to copy the post so that component state changes work properly
postList.posts[post.id] = Object.assign({}, post, {
state: Constants.POST_DELETED,
filenames: []
});
}
}
removePost(post) {
const channelId = post.channel_id;
this.makePostsInfo(channelId);
const postList = this.postsInfo[channelId].postList;
if (isPostListNull(postList)) {
return;
}
if (post.id in postList.posts) {
Reflect.deleteProperty(postList.posts, post.id);
}
const index = postList.order.indexOf(post.id);
if (index !== -1) {
postList.order.splice(index, 1);
}
for (const pid in postList.posts) {
if (!postList.posts.hasOwnProperty(pid)) {
continue;
}
if (postList.posts[pid].root_id === post.id) {
Reflect.deleteProperty(postList.posts, pid);
const commentIndex = postList.order.indexOf(pid);
if (commentIndex !== -1) {
postList.order.splice(commentIndex, 1);
}
}
}
this.postsInfo[channelId].postList = postList;
}
getPendingPosts(channelId) {
if (this.postsInfo.hasOwnProperty(channelId)) {
return this.postsInfo[channelId].pendingPosts;
}
return null;
}
storePendingPost(post) {
const copyPost = JSON.parse(JSON.stringify(post));
copyPost.state = Constants.POST_LOADING;
const postList = makePostListNonNull(this.getPendingPosts(copyPost.channel_id));
postList.posts[copyPost.pending_post_id] = copyPost;
postList.order.unshift(copyPost.pending_post_id);
this.makePostsInfo(copyPost.channel_id);
this.postsInfo[copyPost.channel_id].pendingPosts = postList;
this.emitChange();
}
removePendingPost(channelId, pendingPostId) {
const postList = makePostListNonNull(this.getPendingPosts(channelId));
Reflect.deleteProperty(postList.posts, pendingPostId);
const index = postList.order.indexOf(pendingPostId);
if (index === -1) {
return;
}
postList.order.splice(index, 1);
this.postsInfo[channelId].pendingPosts = postList;
this.emitChange();
}
clearPendingPosts(channelId) {
if (this.postsInfo.hasOwnProperty(channelId)) {
Reflect.deleteProperty(this.postsInfo[channelId], 'pendingPosts');
}
}
updatePendingPost(post) {
const copyPost = JSON.parse(JSON.stringify(post));
const postList = makePostListNonNull(this.getPendingPosts(copyPost.channel_id));
if (postList.order.indexOf(copyPost.pending_post_id) === -1) {
return;
}
postList.posts[copyPost.pending_post_id] = copyPost;
this.postsInfo[copyPost.channel_id].pendingPosts = postList;
this.emitChange();
}
storeSelectedPostId(postId) {
this.selectedPostId = postId;
}
getSelectedPostId() {
return this.selectedPostId;
}
getSelectedPost() {
if (this.selectedPostId == null) {
return null;
}
for (const k in this.postsInfo) {
if (this.postsInfo[k].postList.posts.hasOwnProperty(this.selectedPostId)) {
return this.postsInfo[k].postList.posts[this.selectedPostId];
}
}
return null;
}
getSelectedPostThread() {
if (this.selectedPostId == null) {
return null;
}
let posts;
let pendingPosts;
for (const k in this.postsInfo) {
if (this.postsInfo[k].postList.posts.hasOwnProperty(this.selectedPostId)) {
posts = this.postsInfo[k].postList.posts;
if (this.postsInfo[k].pendingPosts != null) {
pendingPosts = this.postsInfo[k].pendingPosts.posts;
}
}
}
const threadPosts = {};
const rootId = this.selectedPostId;
for (const k in posts) {
if (posts[k].root_id === rootId) {
threadPosts[k] = JSON.parse(JSON.stringify(posts[k]));
}
}
for (const k in pendingPosts) {
if (pendingPosts[k].root_id === rootId) {
threadPosts[k] = JSON.parse(JSON.stringify(pendingPosts[k]));
}
}
return threadPosts;
}
emitSelectedPostChange(fromSearch) {
this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch);
}
addSelectedPostChangeListener(callback) {
this.on(SELECTED_POST_CHANGE_EVENT, callback);
}
removeSelectedPostChangeListener(callback) {
this.removeListener(SELECTED_POST_CHANGE_EVENT, callback);
}
getCurrentUsersLatestPost(channelId, rootId) {
const userId = UserStore.getCurrentId();
var postList = makePostListNonNull(this.getAllPosts(channelId));
var i = 0;
var len = postList.order.length;
var lastPost = null;
for (i; i < len; i++) {
const post = postList.posts[postList.order[i]];
if (post.user_id === userId && (post.props && !post.props.from_webhook || !post.props)) {
if (rootId) {
if (post.root_id === rootId || post.id === rootId) {
lastPost = post;
break;
}
} else {
lastPost = post;
break;
}
}
}
return lastPost;
}
getEmptyDraft() {
return {message: '', uploadsInProgress: [], previews: []};
}
storeCurrentDraft(draft) {
var channelId = ChannelStore.getCurrentId();
BrowserStore.setGlobalItem('draft_' + channelId, draft);
}
getCurrentDraft() {
var channelId = ChannelStore.getCurrentId();
return this.getDraft(channelId);
}
storeDraft(channelId, draft) {
BrowserStore.setGlobalItem('draft_' + channelId, draft);
}
getDraft(channelId) {
return BrowserStore.getGlobalItem('draft_' + channelId, this.getEmptyDraft());
}
storeCommentDraft(parentPostId, draft) {
BrowserStore.setGlobalItem('comment_draft_' + parentPostId, draft);
}
getCommentDraft(parentPostId) {
return BrowserStore.getGlobalItem('comment_draft_' + parentPostId, this.getEmptyDraft());
}
clearDraftUploads() {
BrowserStore.actionOnGlobalItemsWithPrefix('draft_', (key, value) => {
if (value) {
value.uploadsInProgress = [];
BrowserStore.setItem(key, value);
}
});
}
clearCommentDraftUploads() {
BrowserStore.actionOnGlobalItemsWithPrefix('comment_draft_', (key, value) => {
if (value) {
value.uploadsInProgress = [];
BrowserStore.setItem(key, value);
}
});
}
getCommentCount(post) {
const posts = this.getAllPosts(post.channel_id).posts;
let commentCount = 0;
for (const id in posts) {
if (posts.hasOwnProperty(id)) {
if (posts[id].root_id === post.id) {
commentCount += 1;
}
}
}
return commentCount;
}
}
var PostStore = new PostStoreClass();
PostStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_POSTS: {
const id = PostStore.currentFocusedPostId == null ? action.id : PostStore.currentFocusedPostId;
PostStore.checkBounds(id, action.numRequested, makePostListNonNull(action.post_list), action.before);
PostStore.storePosts(id, makePostListNonNull(action.post_list));
PostStore.emitChange();
break;
}
case ActionTypes.RECEIVED_FOCUSED_POST:
PostStore.clearChannelVisibility(action.postId, false);
PostStore.storeFocusedPost(action.postId, makePostListNonNull(action.post_list));
PostStore.emitChange();
break;
case ActionTypes.RECEIVED_POST:
PostStore.storePost(action.post);
PostStore.emitChange();
break;
case ActionTypes.RECEIVED_EDIT_POST:
PostStore.emitEditPost(action);
PostStore.emitChange();
break;
case ActionTypes.CLICK_CHANNEL:
PostStore.clearFocusedPost();
PostStore.clearChannelVisibility(action.id, true);
break;
case ActionTypes.CREATE_POST:
PostStore.storePendingPost(action.post);
PostStore.storeDraft(action.post.channel_id, null);
PostStore.jumpPostsViewToBottom();
break;
case ActionTypes.POST_DELETED:
PostStore.deletePost(action.post);
PostStore.emitChange();
break;
case ActionTypes.REMOVE_POST:
PostStore.removePost(action.post);
PostStore.emitChange();
break;
case ActionTypes.RECEIVED_POST_SELECTED:
PostStore.storeSelectedPostId(action.postId);
PostStore.emitSelectedPostChange(action.from_search);
break;
default:
}
});
export default PostStore;
function makePostListNonNull(pl) {
var postList = pl;
if (postList == null) {
postList = {order: [], posts: {}};
}
if (postList.order == null) {
postList.order = [];
}
if (postList.posts == null) {
postList.posts = {};
}
return postList;
}
function isPostListNull(pl) {
if (pl == null) {
return true;
}
if (pl.posts == null) {
return true;
}
if (pl.order == null) {
return true;
}
return false;
}

178
webapp/stores/preference_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,178 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import BrowserStore from './browser_store.jsx';
import EventEmitter from 'events';
import UserStore from 'stores/user_store.jsx';
const CHANGE_EVENT = 'change';
function getPreferenceKey(category, name) {
return `${category}-${name}`;
}
function getPreferenceKeyForModel(preference) {
return `${preference.category}-${preference.name}`;
}
class PreferenceStoreClass extends EventEmitter {
constructor() {
super();
this.getAllPreferences = this.getAllPreferences.bind(this);
this.get = this.get.bind(this);
this.getBool = this.getBool.bind(this);
this.getInt = this.getInt.bind(this);
this.getPreference = this.getPreference.bind(this);
this.getCategory = this.getCategory.bind(this);
this.getPreferencesWhere = this.getPreferencesWhere.bind(this);
this.setAllPreferences = this.setAllPreferences.bind(this);
this.setPreference = this.setPreference.bind(this);
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.handleEventPayload = this.handleEventPayload.bind(this);
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
}
getAllPreferences() {
return new Map(BrowserStore.getItem('preferences', []));
}
get(category, name, defaultValue = '') {
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
if (!preference) {
return defaultValue;
}
return preference.value || defaultValue;
}
getBool(category, name, defaultValue = false) {
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
if (!preference) {
return defaultValue;
}
// prevent a non-false default value from being returned instead of an actual false value
if (preference.value === 'false') {
return false;
}
return (preference.value !== 'false') || defaultValue;
}
getInt(category, name, defaultValue = 0) {
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
if (!preference) {
return defaultValue;
}
// prevent a non-zero default value from being returned instead of an actual 0 value
if (preference.value === '0') {
return 0;
}
return parseInt(preference.value, 10) || defaultValue;
}
getPreference(category, name, defaultValue = {}) {
return this.getAllPreferences().get(getPreferenceKey(category, name)) || defaultValue;
}
getCategory(category) {
return this.getPreferencesWhere((preference) => (preference.category === category));
}
getPreferencesWhere(pred) {
const all = this.getAllPreferences();
const preferences = [];
for (const [, preference] of all) {
if (pred(preference)) {
preferences.push(preference);
}
}
return preferences;
}
setAllPreferences(preferences) {
// note that we store the preferences as an array of key-value pairs so that we can deserialize
// it as a proper Map instead of an object
BrowserStore.setItem('preferences', [...preferences]);
}
setPreference(category, name, value) {
const preferences = this.getAllPreferences();
const key = getPreferenceKey(category, name);
let preference = preferences.get(key);
if (!preference) {
preference = {
user_id: UserStore.getCurrentId(),
category,
name
};
}
preference.value = value;
preferences.set(key, preference);
this.setAllPreferences(preferences);
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);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
handleEventPayload(payload) {
const action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_PREFERENCE: {
const preference = action.preference;
this.setPreference(preference.category, preference.name, preference.value);
this.emitChange();
break;
}
case ActionTypes.RECEIVED_PREFERENCES:
this.setPreferences(action.preferences);
this.emitChange();
break;
}
}
}
const PreferenceStore = new PreferenceStoreClass();
export default PreferenceStore;
window.PreferenceStore = PreferenceStore;

137
webapp/stores/search_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,137 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import BrowserStore from 'stores/browser_store.jsx';
import Constants from 'utils/constants.jsx';
var ActionTypes = Constants.ActionTypes;
var CHANGE_EVENT = 'change';
var SEARCH_CHANGE_EVENT = 'search_change';
var SEARCH_TERM_CHANGE_EVENT = 'search_term_change';
var SHOW_SEARCH_EVENT = 'show_search';
class SearchStoreClass extends EventEmitter {
constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.emitSearchChange = this.emitSearchChange.bind(this);
this.addSearchChangeListener = this.addSearchChangeListener.bind(this);
this.removeSearchChangeListener = this.removeSearchChangeListener.bind(this);
this.emitSearchTermChange = this.emitSearchTermChange.bind(this);
this.addSearchTermChangeListener = this.addSearchTermChangeListener.bind(this);
this.removeSearchTermChangeListener = this.removeSearchTermChangeListener.bind(this);
this.emitShowSearch = this.emitShowSearch.bind(this);
this.addShowSearchListener = this.addShowSearchListener.bind(this);
this.removeShowSearchListener = this.removeShowSearchListener.bind(this);
this.getSearchResults = this.getSearchResults.bind(this);
this.getIsMentionSearch = this.getIsMentionSearch.bind(this);
this.storeSearchTerm = this.storeSearchTerm.bind(this);
this.getSearchTerm = this.getSearchTerm.bind(this);
this.storeSearchResults = this.storeSearchResults.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitSearchChange() {
this.emit(SEARCH_CHANGE_EVENT);
}
addSearchChangeListener(callback) {
this.on(SEARCH_CHANGE_EVENT, callback);
}
removeSearchChangeListener(callback) {
this.removeListener(SEARCH_CHANGE_EVENT, callback);
}
emitSearchTermChange(doSearch, isMentionSearch) {
this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch);
}
addSearchTermChangeListener(callback) {
this.on(SEARCH_TERM_CHANGE_EVENT, callback);
}
removeSearchTermChangeListener(callback) {
this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback);
}
emitShowSearch() {
this.emit(SHOW_SEARCH_EVENT);
}
addShowSearchListener(callback) {
this.on(SHOW_SEARCH_EVENT, callback);
}
removeShowSearchListener(callback) {
this.removeListener(SHOW_SEARCH_EVENT, callback);
}
getSearchResults() {
return BrowserStore.getItem('search_results');
}
getIsMentionSearch() {
return BrowserStore.getItem('is_mention_search');
}
storeSearchTerm(term) {
BrowserStore.setItem('search_term', term);
}
getSearchTerm() {
return BrowserStore.getItem('search_term');
}
storeSearchResults(results, isMentionSearch) {
BrowserStore.setItem('search_results', results);
BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch));
}
}
var SearchStore = new SearchStoreClass();
SearchStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_SEARCH:
SearchStore.storeSearchResults(action.results, action.is_mention_search);
SearchStore.emitSearchChange();
break;
case ActionTypes.RECEIVED_SEARCH_TERM:
SearchStore.storeSearchTerm(action.term);
SearchStore.emitSearchTermChange(action.do_search, action.is_mention_search);
break;
case ActionTypes.SHOW_SEARCH:
SearchStore.emitShowSearch();
break;
default:
}
});
export default SearchStore;

343
webapp/stores/socket_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,343 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import $ from 'jquery';
import UserStore from './user_store.jsx';
import PostStore from './post_store.jsx';
import ChannelStore from './channel_store.jsx';
import BrowserStore from './browser_store.jsx';
import ErrorStore from './error_store.jsx';
import EventEmitter from 'events';
import * as Utils from 'utils/utils.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import Constants from 'utils/constants.jsx';
const SocketEvents = Constants.SocketEvents;
const CHANGE_EVENT = 'change';
var conn;
class SocketStoreClass extends EventEmitter {
constructor() {
super();
this.initialize = this.initialize.bind(this);
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.sendMessage = this.sendMessage.bind(this);
this.close = this.close.bind(this);
this.failCount = 0;
this.isInitialize = false;
this.translations = this.getDefaultTranslations();
this.initialize();
}
initialize() {
if (!UserStore.getCurrentId()) {
return;
}
this.setMaxListeners(0);
if (window.WebSocket && !conn) {
var protocol = 'ws://';
if (window.location.protocol === 'https:') {
protocol = 'wss://';
}
var connUrl = protocol + location.host + ((/:\d+/).test(location.host) ? '' : Utils.getWebsocketPort(protocol)) + '/api/v1/websocket';
if (this.failCount === 0) {
console.log('websocket connecting to ' + connUrl); //eslint-disable-line no-console
}
conn = new WebSocket(connUrl);
conn.onopen = () => {
if (this.failCount > 0) {
console.log('websocket re-established connection'); //eslint-disable-line no-console
AsyncClient.getChannels();
AsyncClient.getPosts(ChannelStore.getCurrentId());
}
if (this.isInitialize) {
ErrorStore.clearLastError();
ErrorStore.emitChange();
}
this.isInitialize = true;
this.failCount = 0;
};
conn.onclose = () => {
conn = null;
if (this.failCount === 0) {
console.log('websocket closed'); //eslint-disable-line no-console
}
this.failCount = this.failCount + 1;
if (this.failCount > 7) {
ErrorStore.storeLastError({message: this.translations.socketError});
}
ErrorStore.setConnectionErrorCount(this.failCount);
ErrorStore.emitChange();
setTimeout(
() => {
this.initialize();
},
3000
);
};
conn.onerror = (evt) => {
if (this.failCount <= 1) {
console.log('websocket error'); //eslint-disable-line no-console
console.log(evt); //eslint-disable-line no-console
}
};
conn.onmessage = (evt) => {
const msg = JSON.parse(evt.data);
this.handleMessage(msg);
this.emitChange(msg);
};
}
}
emitChange(msg) {
this.emit(CHANGE_EVENT, msg);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
handleMessage(msg) {
switch (msg.action) {
case SocketEvents.POSTED:
case SocketEvents.EPHEMERAL_MESSAGE:
handleNewPostEvent(msg, this.translations);
break;
case SocketEvents.POST_EDITED:
handlePostEditEvent(msg);
break;
case SocketEvents.POST_DELETED:
handlePostDeleteEvent(msg);
break;
case SocketEvents.NEW_USER:
handleNewUserEvent();
break;
case SocketEvents.USER_ADDED:
handleUserAddedEvent(msg);
break;
case SocketEvents.USER_REMOVED:
handleUserRemovedEvent(msg);
break;
case SocketEvents.CHANNEL_VIEWED:
handleChannelViewedEvent(msg);
break;
case SocketEvents.PREFERENCE_CHANGED:
handlePreferenceChangedEvent(msg);
break;
default:
}
}
sendMessage(msg) {
if (conn && conn.readyState === WebSocket.OPEN) {
conn.send(JSON.stringify(msg));
} else if (!conn || conn.readyState === WebSocket.Closed) {
conn = null;
this.initialize();
}
}
setTranslations(messages) {
this.translations = messages;
}
getDefaultTranslations() {
return ({
socketError: 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.',
someone: 'Someone',
posted: 'Posted',
uploadedImage: ' uploaded an image',
uploadedFile: ' uploaded a file',
something: ' did something new',
wrote: ' wrote: '
});
}
close() {
if (conn && conn.readyState === WebSocket.OPEN) {
conn.close();
}
}
}
function handleNewPostEvent(msg, translations) {
// Store post
const post = JSON.parse(msg.props.post);
GlobalActions.emitPostRecievedEvent(post);
// Update channel state
if (ChannelStore.getCurrentId() === msg.channel_id) {
if (window.isActive) {
AsyncClient.updateLastViewedAt();
} else {
AsyncClient.getChannel(msg.channel_id);
}
} else if (UserStore.getCurrentId() !== msg.user_id || post.type !== Constants.POST_TYPE_JOIN_LEAVE) {
AsyncClient.getChannel(msg.channel_id);
}
// Send desktop notification
if ((UserStore.getCurrentId() !== msg.user_id || post.props.from_webhook === 'true') && !Utils.isSystemMessage(post)) {
const msgProps = msg.props;
let mentions = [];
if (msgProps.mentions) {
mentions = JSON.parse(msg.props.mentions);
}
const channel = ChannelStore.get(msg.channel_id);
const user = UserStore.getCurrentUser();
const member = ChannelStore.getMember(msg.channel_id);
let notifyLevel = member && member.notify_props ? member.notify_props.desktop : 'default';
if (notifyLevel === 'default') {
notifyLevel = user.notify_props.desktop;
}
if (notifyLevel === 'none') {
return;
} else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== Constants.DM_CHANNEL) {
return;
}
let username = translations.someone;
if (post.props.override_username && global.window.mm_config.EnablePostUsernameOverride === 'true') {
username = post.props.override_username;
} else if (UserStore.hasProfile(msg.user_id)) {
username = UserStore.getProfile(msg.user_id).username;
}
let title = translations.posted;
if (channel) {
title = channel.display_name;
}
let notifyText = post.message.replace(/\n+/g, ' ');
if (notifyText.length > 50) {
notifyText = notifyText.substring(0, 49) + '...';
}
if (notifyText.length === 0) {
if (msgProps.image) {
Utils.notifyMe(title, username + translations.uploadedImage, channel);
} else if (msgProps.otherFile) {
Utils.notifyMe(title, username + translations.uploadedFile, channel);
} else {
Utils.notifyMe(title, username + translations.something, channel);
}
} else {
Utils.notifyMe(title, username + translations.wrote + notifyText, channel);
}
if (!user.notify_props || user.notify_props.desktop_sound === 'true') {
Utils.ding();
}
}
}
function handlePostEditEvent(msg) {
// Store post
const post = JSON.parse(msg.props.post);
PostStore.storePost(post);
PostStore.emitChange();
// Update channel state
if (ChannelStore.getCurrentId() === msg.channel_id) {
if (window.isActive) {
AsyncClient.updateLastViewedAt();
}
}
}
function handlePostDeleteEvent(msg) {
const post = JSON.parse(msg.props.post);
GlobalActions.emitPostDeletedEvent(post);
}
function handleNewUserEvent() {
AsyncClient.getProfiles();
AsyncClient.getChannelExtraInfo();
}
function handleUserAddedEvent(msg) {
if (ChannelStore.getCurrentId() === msg.channel_id) {
AsyncClient.getChannelExtraInfo();
}
if (UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannel(msg.channel_id);
}
}
function handleUserRemovedEvent(msg) {
if (UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannels();
if (msg.props.remover_id !== msg.user_id &&
msg.channel_id === ChannelStore.getCurrentId() &&
$('#removed_from_channel').length > 0) {
var sentState = {};
sentState.channelName = ChannelStore.getCurrent().display_name;
sentState.remover = UserStore.getProfile(msg.props.remover_id).username;
BrowserStore.setItem('channel-removed-state', sentState);
$('#removed_from_channel').modal('show');
}
} else if (ChannelStore.getCurrentId() === msg.channel_id) {
AsyncClient.getChannelExtraInfo();
}
}
function handleChannelViewedEvent(msg) {
// Useful for when multiple devices have the app open to different channels
if (ChannelStore.getCurrentId() !== msg.channel_id && UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannel(msg.channel_id);
}
}
function handlePreferenceChangedEvent(msg) {
const preference = JSON.parse(msg.props.preference);
GlobalActions.emitPreferenceChangedEvent(preference);
}
var SocketStore = new SocketStoreClass();
export default SocketStore;
window.SocketStore = SocketStore;

261
webapp/stores/suggestion_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,261 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import Constants from 'utils/constants.jsx';
import EventEmitter from 'events';
const ActionTypes = Constants.ActionTypes;
const COMPLETE_WORD_EVENT = 'complete_word';
const PRETEXT_CHANGED_EVENT = 'pretext_changed';
const SUGGESTIONS_CHANGED_EVENT = 'suggestions_changed';
class SuggestionStore extends EventEmitter {
constructor() {
super();
this.addSuggestionsChangedListener = this.addSuggestionsChangedListener.bind(this);
this.removeSuggestionsChangedListener = this.removeSuggestionsChangedListener.bind(this);
this.emitSuggestionsChanged = this.emitSuggestionsChanged.bind(this);
this.addPretextChangedListener = this.addPretextChangedListener.bind(this);
this.removePretextChangedListener = this.removePretextChangedListener.bind(this);
this.emitPretextChanged = this.emitPretextChanged.bind(this);
this.addCompleteWordListener = this.addCompleteWordListener.bind(this);
this.removeCompleteWordListener = this.removeCompleteWordListener.bind(this);
this.emitCompleteWord = this.emitCompleteWord.bind(this);
this.handleEventPayload = this.handleEventPayload.bind(this);
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
// this.suggestions stores the state of all SuggestionBoxes by mapping their unique identifier to an
// object with the following fields:
// pretext: the text before the cursor
// matchedPretext: the text before the cursor that will be replaced if an autocomplete term is selected
// terms: a list of strings which the previously typed text may be replaced by
// items: a list of objects backing the terms which may be used in rendering
// components: a list of react components that can be used to render their corresponding item
// selection: the term currently selected by the keyboard
this.suggestions = new Map();
}
addSuggestionsChangedListener(id, callback) {
this.on(SUGGESTIONS_CHANGED_EVENT + id, callback);
}
removeSuggestionsChangedListener(id, callback) {
this.removeListener(SUGGESTIONS_CHANGED_EVENT + id, callback);
}
emitSuggestionsChanged(id) {
this.emit(SUGGESTIONS_CHANGED_EVENT + id);
}
addPretextChangedListener(id, callback) {
this.on(PRETEXT_CHANGED_EVENT + id, callback);
}
removePretextChangedListener(id, callback) {
this.removeListener(PRETEXT_CHANGED_EVENT + id, callback);
}
emitPretextChanged(id, pretext) {
this.emit(PRETEXT_CHANGED_EVENT + id, pretext);
}
addCompleteWordListener(id, callback) {
this.on(COMPLETE_WORD_EVENT + id, callback);
}
removeCompleteWordListener(id, callback) {
this.removeListener(COMPLETE_WORD_EVENT + id, callback);
}
emitCompleteWord(id, term) {
this.emit(COMPLETE_WORD_EVENT + id, term);
}
registerSuggestionBox(id) {
this.suggestions.set(id, {
pretext: '',
matchedPretext: '',
terms: [],
items: [],
components: [],
selection: ''
});
}
unregisterSuggestionBox(id) {
this.suggestions.delete(id);
}
clearSuggestions(id) {
const suggestion = this.suggestions.get(id);
suggestion.matchedPretext = '';
suggestion.terms = [];
suggestion.items = [];
suggestion.components = [];
}
clearSelection(id) {
const suggestion = this.suggestions.get(id);
suggestion.selection = '';
}
hasSuggestions(id) {
return this.suggestions.get(id).terms.length > 0;
}
setPretext(id, pretext) {
const suggestion = this.suggestions.get(id);
suggestion.pretext = pretext;
}
setMatchedPretext(id, matchedPretext) {
const suggestion = this.suggestions.get(id);
suggestion.matchedPretext = matchedPretext;
}
addSuggestion(id, term, item, component) {
const suggestion = this.suggestions.get(id);
suggestion.terms.push(term);
suggestion.items.push(item);
suggestion.components.push(component);
}
addSuggestions(id, terms, items, component) {
const suggestion = this.suggestions.get(id);
suggestion.terms.push(...terms);
suggestion.items.push(...items);
for (let i = 0; i < terms.length; i++) {
suggestion.components.push(component);
}
}
// make sure that if suggestions exist, then one of them is selected. return true if the selection changes.
ensureSelectionExists(id) {
const suggestion = this.suggestions.get(id);
if (suggestion.terms.length > 0) {
// if the current selection is no longer in the map, select the first term in the list
if (!suggestion.selection || suggestion.terms.indexOf(suggestion.selection) === -1) {
suggestion.selection = suggestion.terms[0];
return true;
}
} else if (suggestion.selection) {
suggestion.selection = '';
return true;
}
return false;
}
getPretext(id) {
return this.suggestions.get(id).pretext;
}
getMatchedPretext(id) {
return this.suggestions.get(id).matchedPretext;
}
getItems(id) {
return this.suggestions.get(id).items;
}
getTerms(id) {
return this.suggestions.get(id).terms;
}
getComponents(id) {
return this.suggestions.get(id).components;
}
getSelection(id) {
return this.suggestions.get(id).selection;
}
selectNext(id) {
this.setSelectionByDelta(id, 1);
}
selectPrevious(id) {
this.setSelectionByDelta(id, -1);
}
setSelectionByDelta(id, delta) {
const suggestion = this.suggestions.get(id);
let selectionIndex = suggestion.terms.indexOf(suggestion.selection);
if (selectionIndex === -1) {
// this should never happen since selection should always be in terms
throw new Error('selection is not in terms');
}
selectionIndex += delta;
if (selectionIndex < 0) {
selectionIndex = 0;
} else if (selectionIndex > suggestion.terms.length - 1) {
selectionIndex = suggestion.terms.length - 1;
}
suggestion.selection = suggestion.terms[selectionIndex];
}
handleEventPayload(payload) {
const {type, id, ...other} = payload.action; // eslint-disable-line no-use-before-define
switch (type) {
case ActionTypes.SUGGESTION_PRETEXT_CHANGED:
this.clearSuggestions(id);
this.setPretext(id, other.pretext);
this.emitPretextChanged(id, other.pretext);
this.ensureSelectionExists(id);
this.emitSuggestionsChanged(id);
break;
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
if (this.getMatchedPretext(id) === '') {
this.setMatchedPretext(id, other.matchedPretext);
// ensure the matched pretext hasn't changed so that we don't receive suggestions for outdated pretext
this.addSuggestions(id, other.terms, other.items, other.component);
this.ensureSelectionExists(id);
this.emitSuggestionsChanged(id);
}
break;
case ActionTypes.SUGGESTION_CLEAR_SUGGESTIONS:
this.clearSuggestions(id);
this.clearSelection(id);
this.emitSuggestionsChanged(id);
break;
case ActionTypes.SUGGESTION_SELECT_NEXT:
this.selectNext(id);
this.emitSuggestionsChanged(id);
break;
case ActionTypes.SUGGESTION_SELECT_PREVIOUS:
this.selectPrevious(id);
this.emitSuggestionsChanged(id);
break;
case ActionTypes.SUGGESTION_COMPLETE_WORD:
this.emitCompleteWord(id, other.term || this.getSelection(id), this.getMatchedPretext(id));
this.setPretext(id, '');
this.clearSuggestions(id);
this.clearSelection(id);
this.emitSuggestionsChanged(id);
break;
}
}
}
export default new SuggestionStore();

142
webapp/stores/team_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,142 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
var Utils;
function getWindowLocationOrigin() {
if (!Utils) {
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
}
return Utils.getWindowLocationOrigin();
}
class TeamStoreClass extends EventEmitter {
constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.get = this.get.bind(this);
this.getByName = this.getByName.bind(this);
this.getAll = this.getAll.bind(this);
this.getCurrentId = this.getCurrentId.bind(this);
this.getCurrent = this.getCurrent.bind(this);
this.getCurrentTeamUrl = this.getCurrentTeamUrl.bind(this);
this.getCurrentInviteLink = this.getCurrentInviteLink.bind(this);
this.saveTeam = this.saveTeam.bind(this);
this.teams = {};
this.currentTeamId = '';
}
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
get(id) {
var c = this.getAll();
return c[id];
}
getByName(name) {
var t = this.getAll();
for (var id in t) {
if (t[id].name === name) {
return t[id];
}
}
return null;
}
getAll() {
return this.teams;
}
getCurrentId() {
var team = this.get(this.currentTeamId);
if (team) {
return team.id;
}
return null;
}
getCurrent() {
const team = this.teams[this.currentTeamId];
if (team) {
return team;
}
return null;
}
getCurrentTeamUrl() {
if (this.getCurrent()) {
return getWindowLocationOrigin() + '/' + this.getCurrent().name;
}
return null;
}
getCurrentInviteLink() {
const current = this.getCurrent();
if (current) {
return getWindowLocationOrigin() + '/signup_user_complete/?id=' + current.invite_id;
}
return '';
}
saveTeam(team) {
this.teams[team.id] = team;
}
saveTeams(teams) {
this.teams = teams;
}
saveMyTeam(team) {
this.saveTeam(team);
this.currentTeamId = team.id;
}
}
var TeamStore = new TeamStoreClass();
TeamStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_MY_TEAM:
TeamStore.saveMyTeam(action.team);
TeamStore.emitChange();
break;
case ActionTypes.RECEIVED_ALL_TEAMS:
TeamStore.saveTeams(action.teams);
TeamStore.emitChange();
break;
default:
}
});
export default TeamStore;

305
webapp/stores/user_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,305 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
import BrowserStore from './browser_store.jsx';
const CHANGE_EVENT = 'change';
const CHANGE_EVENT_SESSIONS = 'change_sessions';
const CHANGE_EVENT_AUDITS = 'change_audits';
const CHANGE_EVENT_STATUSES = 'change_statuses';
class UserStoreClass extends EventEmitter {
constructor() {
super();
this.profileCache = null;
this.currentUserId = '';
}
emitChange(userId) {
this.emit(CHANGE_EVENT, userId);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitSessionsChange() {
this.emit(CHANGE_EVENT_SESSIONS);
}
addSessionsChangeListener(callback) {
this.on(CHANGE_EVENT_SESSIONS, callback);
}
removeSessionsChangeListener(callback) {
this.removeListener(CHANGE_EVENT_SESSIONS, callback);
}
emitAuditsChange() {
this.emit(CHANGE_EVENT_AUDITS);
}
addAuditsChangeListener(callback) {
this.on(CHANGE_EVENT_AUDITS, callback);
}
removeAuditsChangeListener(callback) {
this.removeListener(CHANGE_EVENT_AUDITS, callback);
}
emitStatusesChange() {
this.emit(CHANGE_EVENT_STATUSES);
}
addStatusesChangeListener(callback) {
this.on(CHANGE_EVENT_STATUSES, callback);
}
removeStatusesChangeListener(callback) {
this.removeListener(CHANGE_EVENT_STATUSES, callback);
}
getCurrentUser() {
return this.getProfiles()[this.currentUserId];
}
setCurrentUser(user) {
this.saveProfile(user);
this.currentUserId = user.id;
global.window.mm_current_user_id = this.currentUserId;
}
getCurrentId() {
var user = this.getCurrentUser();
if (user) {
return user.id;
}
return null;
}
getLastEmail() {
return BrowserStore.getGlobalItem('last_email', '');
}
setLastEmail(email) {
BrowserStore.setGlobalItem('last_email', email);
}
getLastUsername() {
return BrowserStore.getGlobalItem('last_username', '');
}
setLastUsername(username) {
BrowserStore.setGlobalItem('last_username', username);
}
hasProfile(userId) {
return this.getProfiles()[userId] != null;
}
getProfile(userId) {
if (userId === this.getCurrentId()) {
return this.getCurrentUser();
}
return this.getProfiles()[userId];
}
getProfileByUsername(username) {
return this.getProfilesUsernameMap()[username];
}
getProfilesUsernameMap() {
var profileUsernameMap = {};
var profiles = this.getProfiles();
for (var key in profiles) {
if (profiles.hasOwnProperty(key)) {
var profile = profiles[key];
profileUsernameMap[profile.username] = profile;
}
}
return profileUsernameMap;
}
getProfiles() {
if (this.profileCache !== null) {
return this.profileCache;
}
return BrowserStore.getItem('profiles', {});
}
getActiveOnlyProfiles(skipCurrent) {
const active = {};
const profiles = this.getProfiles();
const currentId = this.getCurrentId();
for (var key in profiles) {
if (!(profiles[key].id === currentId && skipCurrent) && profiles[key].delete_at === 0) {
active[key] = profiles[key];
}
}
return active;
}
getActiveOnlyProfileList() {
const profileMap = this.getActiveOnlyProfiles();
const profiles = [];
const currentId = this.getCurrentId();
for (const id in profileMap) {
if (profileMap.hasOwnProperty(id) && id !== currentId) {
profiles.push(profileMap[id]);
}
}
return profiles;
}
saveProfile(profile) {
var ps = this.getProfiles();
ps[profile.id] = profile;
this.profileCache = ps;
BrowserStore.setItem('profiles', ps);
}
saveProfiles(profiles) {
const currentId = this.getCurrentId();
if (this.profileCache) {
const currentUser = this.profileCache[currentId];
if (currentUser) {
if (currentId in profiles) {
delete profiles[currentId];
}
this.profileCache = profiles;
this.profileCache[currentId] = currentUser;
} else {
this.profileCache = profiles;
}
} else {
this.profileCache = profiles;
}
BrowserStore.setItem('profiles', profiles);
}
setSessions(sessions) {
BrowserStore.setItem('sessions', sessions);
}
getSessions() {
return BrowserStore.getItem('sessions', {loading: true});
}
setAudits(audits) {
BrowserStore.setItem('audits', audits);
}
getAudits() {
return BrowserStore.getItem('audits', {loading: true});
}
getCurrentMentionKeys() {
return this.getMentionKeys(this.getCurrentId());
}
getMentionKeys(id) {
var user = this.getProfile(id);
var keys = [];
if (!user || !user.notify_props) {
return keys;
}
if (user.notify_props.mention_keys) {
keys = keys.concat(user.notify_props.mention_keys.split(','));
}
if (user.notify_props.first_name === 'true' && user.first_name) {
keys.push(user.first_name);
}
if (user.notify_props.all === 'true') {
keys.push('@all');
}
if (user.notify_props.channel === 'true') {
keys.push('@channel');
}
return keys;
}
setStatuses(statuses) {
this.pSetStatuses(statuses);
this.emitStatusesChange();
}
pSetStatuses(statuses) {
BrowserStore.setItem('statuses', statuses);
}
setStatus(userId, status) {
var statuses = this.getStatuses();
statuses[userId] = status;
this.pSetStatuses(statuses);
this.emitStatusesChange();
}
getStatuses() {
return BrowserStore.getItem('statuses', {});
}
getStatus(id) {
return this.getStatuses()[id];
}
}
var UserStore = new UserStoreClass();
UserStore.setMaxListeners(15);
UserStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECEIVED_PROFILES:
UserStore.saveProfiles(action.profiles);
UserStore.emitChange();
break;
case ActionTypes.RECEIVED_ME:
UserStore.setCurrentUser(action.me);
UserStore.emitChange(action.me.id);
break;
case ActionTypes.RECEIVED_SESSIONS:
UserStore.setSessions(action.sessions);
UserStore.emitSessionsChange();
break;
case ActionTypes.RECEIVED_AUDITS:
UserStore.setAudits(action.audits);
UserStore.emitAuditsChange();
break;
case ActionTypes.RECEIVED_STATUSES:
UserStore.pSetStatuses(action.statuses);
UserStore.emitStatusesChange();
break;
default:
}
});
export {UserStore as default};