PLT-3145 Custom Emojis (#3381)
* Reorganized Backstage code to use a view controller and separated it from integrations code * Renamed InstalledIntegrations component to BackstageList * Added EmojiList page * Added AddEmoji page * Added custom emoji to autocomplete and text formatter * Moved system emoji to EmojiStore * Stopped trying to get emoji before logging in * Rerender posts when emojis change * Fixed submit handler on backstage pages to properly support enter * Removed debugging code * Updated javascript driver * Fixed unit tests * Fixed backstage routes * Added clientside validation to prevent users from creating an emoji with the same name as a system one * Fixed AddEmoji page to properly redirect when an emoji is created successfully * Fixed updating emoji list when an emoji is deleted * Added type prop to BackstageList to properly support using a table for the list * Added help text to EmojiList * Fixed backstage on smaller screen sizes * Disable custom emoji by default * Improved restrictions on creating emojis * Fixed non-admin users seeing the option to delete each other's emojis * Fixing gofmt * Fixed emoji unit tests * Fixed trying to get emoji from the server when it's disabled
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
a65f1fc266
Коммит
dc2f2a8001
135
webapp/stores/emoji_store.jsx
Обычный файл
135
webapp/stores/emoji_store.jsx
Обычный файл
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2016 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';
|
||||
|
||||
import EmojiJson from 'utils/emoji.json';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'changed';
|
||||
|
||||
class EmojiStore extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload.bind(this));
|
||||
|
||||
this.emojis = new Map(EmojiJson);
|
||||
this.systemEmojis = new Map(EmojiJson);
|
||||
|
||||
this.unicodeEmojis = new Map();
|
||||
for (const [, emoji] of this.systemEmojis) {
|
||||
if (emoji.unicode) {
|
||||
this.unicodeEmojis.set(emoji.unicode, emoji);
|
||||
}
|
||||
}
|
||||
|
||||
this.receivedCustomEmojis = false;
|
||||
this.customEmojis = new Map();
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
hasReceivedCustomEmojis() {
|
||||
return this.receivedCustomEmojis;
|
||||
}
|
||||
|
||||
setCustomEmojis(customEmojis) {
|
||||
this.customEmojis = new Map();
|
||||
|
||||
for (const emoji of customEmojis) {
|
||||
this.addCustomEmoji(emoji);
|
||||
}
|
||||
|
||||
// add custom emojis to the map first so that they can't override system ones
|
||||
this.emojis = new Map([...this.customEmojis, ...this.systemEmojis]);
|
||||
}
|
||||
|
||||
addCustomEmoji(emoji) {
|
||||
this.customEmojis.set(emoji.name, emoji);
|
||||
}
|
||||
|
||||
removeCustomEmoji(id) {
|
||||
for (const [name, emoji] of this.customEmojis) {
|
||||
if (emoji.id === id) {
|
||||
this.customEmojis.delete(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSystemEmojis() {
|
||||
return this.systemEmojis;
|
||||
}
|
||||
|
||||
getCustomEmojiMap() {
|
||||
return this.customEmojis;
|
||||
}
|
||||
|
||||
getEmojis() {
|
||||
return this.emojis;
|
||||
}
|
||||
|
||||
has(name) {
|
||||
return this.emojis.has(name);
|
||||
}
|
||||
|
||||
get(name) {
|
||||
// prioritize system emojis so that custom ones can't override them
|
||||
return this.emojis.get(name);
|
||||
}
|
||||
|
||||
hasUnicode(codepoint) {
|
||||
return this.unicodeEmojis.has(codepoint);
|
||||
}
|
||||
|
||||
getUnicode(codepoint) {
|
||||
return this.unicodeEmojis.get(codepoint);
|
||||
}
|
||||
|
||||
getEmojiImageUrl(emoji) {
|
||||
if (emoji.id) {
|
||||
// must match Client.getCustomEmojiImageUrl
|
||||
return `/api/v3/emoji/${emoji.id}`;
|
||||
}
|
||||
|
||||
const filename = emoji.unicode || emoji.filename || emoji.name;
|
||||
|
||||
return Constants.EMOJI_PATH + '/' + filename + '.png';
|
||||
}
|
||||
|
||||
handleEventPayload(payload) {
|
||||
const action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_CUSTOM_EMOJIS:
|
||||
this.setCustomEmojis(action.emojis);
|
||||
this.receivedCustomEmojis = true;
|
||||
this.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_CUSTOM_EMOJI:
|
||||
this.addCustomEmoji(action.emoji);
|
||||
this.emitChange();
|
||||
break;
|
||||
case ActionTypes.REMOVED_CUSTOM_EMOJI:
|
||||
this.removeCustomEmoji(action.id);
|
||||
this.emitChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new EmojiStore();
|
||||
@@ -160,13 +160,16 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
isTeamAdminForCurrentTeam() {
|
||||
return this.isTeamAdmin(UserStore.getCurrentId(), this.getCurrentId());
|
||||
}
|
||||
|
||||
isTeamAdmin(userId, teamId) {
|
||||
if (!Utils) {
|
||||
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
|
||||
}
|
||||
|
||||
const userId = UserStore.getCurrentId();
|
||||
var teamMembers = this.getTeamMembers();
|
||||
const teamMember = teamMembers.find((m) => m.user_id === userId && m.team_id === this.getCurrentId());
|
||||
const teamMember = teamMembers.find((m) => m.user_id === userId && m.team_id === teamId);
|
||||
|
||||
if (teamMember) {
|
||||
return Utils.isAdmin(teamMember.roles);
|
||||
|
||||
Ссылка в новой задаче
Block a user