Update custom emojis endpoint (#852)

* Update emoji endpoint

* Use React.memo on Markdown

* Support RC versions lower than 0.75.0

* Realm migration
This commit is contained in:
Diego Mello 2019-04-26 18:13:07 -03:00 committed by GitHub
parent c340829638
commit 5c1be71fa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 164 additions and 124 deletions

View File

@ -14,98 +14,90 @@ const formatText = text => text.replace(
(match, url, title) => `[${ title }](${ url })`
);
export default class Markdown extends React.Component {
shouldComponentUpdate(nextProps) {
const { msg } = this.props;
return nextProps.msg !== msg;
const Markdown = React.memo(({
msg, customEmojis, style, rules, baseUrl, username, edited, numberOfLines
}) => {
if (!msg) {
return null;
}
render() {
const {
msg, customEmojis, style, rules, baseUrl, username, edited, numberOfLines
} = this.props;
if (!msg) {
return null;
}
let m = formatText(msg);
if (m) {
m = emojify(m, { output: 'unicode' });
}
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim();
if (numberOfLines > 0) {
m = m.replace(/[\n]+/g, '\n').trim();
}
return (
<MarkdownRenderer
rules={{
paragraph: (node, children) => (
// eslint-disable-next-line
<Text key={node.key} style={styles.paragraph} numberOfLines={numberOfLines}>
{children}
{edited ? <Text style={styles.edited}> (edited)</Text> : null}
</Text>
),
mention: (node) => {
const { content, key } = node;
let mentionStyle = styles.mention;
if (content === 'all' || content === 'here') {
mentionStyle = {
...mentionStyle,
...styles.mentionAll
};
} else if (content === username) {
mentionStyle = {
...mentionStyle,
...styles.mentionLoggedUser
};
}
return (
<Text style={mentionStyle} key={key}>
&nbsp;{content}&nbsp;
</Text>
);
},
hashtag: node => (
<Text key={node.key} style={styles.mention}>
&nbsp;#{node.content}&nbsp;
</Text>
),
emoji: (node) => {
if (node.children && node.children.length && node.children[0].content) {
const { content } = node.children[0];
const emojiExtension = customEmojis[content];
if (emojiExtension) {
const emoji = { extension: emojiExtension, content };
return <CustomEmoji key={node.key} baseUrl={baseUrl} style={styles.customEmoji} emoji={emoji} />;
}
return <Text key={node.key}>:{content}:</Text>;
}
return null;
},
hardbreak: () => null,
blocklink: () => null,
image: node => (
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
),
...rules
}}
style={{
paragraph: styles.paragraph,
text: styles.text,
codeInline: styles.codeInline,
codeBlock: styles.codeBlock,
link: styles.link,
...style
}}
plugins={[
new PluginContainer(MarkdownFlowdock),
new PluginContainer(MarkdownEmojiPlugin)
]}
>{m}
</MarkdownRenderer>
);
let m = formatText(msg);
if (m) {
m = emojify(m, { output: 'unicode' });
}
}
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim();
if (numberOfLines > 0) {
m = m.replace(/[\n]+/g, '\n').trim();
}
return (
<MarkdownRenderer
rules={{
paragraph: (node, children) => (
// eslint-disable-next-line
<Text key={node.key} style={styles.paragraph} numberOfLines={numberOfLines}>
{children}
{edited ? <Text style={styles.edited}> (edited)</Text> : null}
</Text>
),
mention: (node) => {
const { content, key } = node;
let mentionStyle = styles.mention;
if (content === 'all' || content === 'here') {
mentionStyle = {
...mentionStyle,
...styles.mentionAll
};
} else if (content === username) {
mentionStyle = {
...mentionStyle,
...styles.mentionLoggedUser
};
}
return (
<Text style={mentionStyle} key={key}>
&nbsp;{content}&nbsp;
</Text>
);
},
hashtag: node => (
<Text key={node.key} style={styles.mention}>
&nbsp;#{node.content}&nbsp;
</Text>
),
emoji: (node) => {
if (node.children && node.children.length && node.children[0].content) {
const { content } = node.children[0];
const emojiExtension = customEmojis[content];
if (emojiExtension) {
const emoji = { extension: emojiExtension, content };
return <CustomEmoji key={node.key} baseUrl={baseUrl} style={styles.customEmoji} emoji={emoji} />;
}
return <Text key={node.key}>:{content}:</Text>;
}
return null;
},
hardbreak: () => null,
blocklink: () => null,
image: node => (
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
),
...rules
}}
style={{
paragraph: styles.paragraph,
text: styles.text,
codeInline: styles.codeInline,
codeBlock: styles.codeBlock,
link: styles.link,
...style
}}
plugins={[
new PluginContainer(MarkdownFlowdock),
new PluginContainer(MarkdownEmojiPlugin)
]}
>{m}
</MarkdownRenderer>
);
}, (prevProps, nextProps) => prevProps.msg === nextProps.msg);
Markdown.propTypes = {
msg: PropTypes.string,
@ -117,3 +109,5 @@ Markdown.propTypes = {
edited: PropTypes.bool,
numberOfLines: PropTypes.number
};
export default Markdown;

View File

@ -1,39 +1,83 @@
import { InteractionManager } from 'react-native';
import semver from 'semver';
import reduxStore from '../createStore';
import database from '../realm';
import * as actions from '../../actions';
import log from '../../utils/log';
const getLastMessage = () => {
const setting = database.objects('customEmojis').sorted('_updatedAt', true)[0];
return setting && setting._updatedAt;
const getUpdatedSince = () => {
const emoji = database.objects('customEmojis').sorted('_updatedAt', true)[0];
return emoji && emoji._updatedAt.toISOString();
};
// TODO: fix api (get emojis by date/version....)
const create = (customEmojis) => {
if (customEmojis && customEmojis.length) {
customEmojis.forEach((emoji) => {
try {
database.create('customEmojis', emoji, true);
} catch (e) {
log('getEmojis create', e);
}
});
}
};
export default async function() {
try {
const lastMessage = getLastMessage();
// RC 0.61.0
const result = await this.sdk.get('emoji-custom');
let { emojis } = result;
emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage);
if (emojis.length === 0) {
return;
}
emojis = this._prepareEmojis(emojis);
InteractionManager.runAfterInteractions(() => {
database.write(() => {
emojis.forEach((emoji) => {
try {
database.create('customEmojis', emoji, true);
} catch (e) {
log('create custom emojis', e);
}
const serverVersion = reduxStore.getState().server.version;
const updatedSince = getUpdatedSince();
// if server version is lower than 0.75.0, fetches from old api
if (semver.lt(serverVersion, '0.75.0')) {
// RC 0.61.0
const result = await this.sdk.get('emoji-custom');
InteractionManager.runAfterInteractions(() => {
let { emojis } = result;
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
database.write(() => {
create(emojis);
});
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(result.emojis)));
});
});
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis)));
} else {
const params = {};
if (updatedSince) {
params.updatedSince = updatedSince;
}
// RC 0.75.0
const result = await this.sdk.get('emoji-custom.list', params);
if (!result.success) {
return;
}
InteractionManager.runAfterInteractions(
() => database.write(() => {
const { emojis } = result;
create(emojis.update);
if (emojis.delete && emojis.delete.length) {
emojis.delete.forEach((emoji) => {
try {
const emojiRecord = database.objectForPrimaryKey('customEmojis', emoji._id);
if (emojiRecord) {
database.delete(emojiRecord);
}
} catch (e) {
log('getEmojis delete', e);
}
});
}
const allEmojis = database.objects('customEmojis');
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(allEmojis)));
})
);
}
} catch (e) {
log('getCustomEmojis', e);
}

View File

@ -24,6 +24,9 @@ export const merge = (subscription, room) => {
subscription.archived = room.archived;
subscription.joinCodeRequired = room.joinCodeRequired;
subscription.broadcast = room.broadcast;
if (!subscription.roles || !subscription.roles.length) {
subscription.roles = [];
}
if (room.muted && room.muted.length) {
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));

View File

@ -286,21 +286,13 @@ const frequentlyUsedEmojiSchema = {
}
};
const customEmojiAliasesSchema = {
name: 'customEmojiAliases',
primaryKey: 'value',
properties: {
value: 'string'
}
};
const customEmojisSchema = {
name: 'customEmojis',
primaryKey: '_id',
properties: {
_id: 'string',
name: 'string',
aliases: { type: 'list', objectType: 'customEmojiAliases' },
aliases: 'string[]',
extension: 'string',
_updatedAt: { type: 'date', optional: true }
}
@ -353,7 +345,6 @@ const schema = [
permissionsSchema,
url,
frequentlyUsedEmojiSchema,
customEmojiAliasesSchema,
customEmojisSchema,
messagesReactionsSchema,
messagesReactionsUsernamesSchema,
@ -428,7 +419,7 @@ class DB {
return this.databases.activeDB = new Realm({
path: `${ path }.realm`,
schema,
schemaVersion: 8,
schemaVersion: 9,
migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 8) {
const newSubs = newRealm.objects('subscriptions');
@ -445,6 +436,14 @@ class DB {
const newThreadMessages = newRealm.objects('threadMessages');
newRealm.delete(newThreadMessages);
}
if (newRealm.schemaVersion === 9) {
const newSubs = newRealm.objects('subscriptions');
newRealm.delete(newSubs);
const newEmojis = newRealm.objects('customEmojis');
newRealm.delete(newEmojis);
const newSettings = newRealm.objects('settings');
newRealm.delete(newSettings);
}
}
});
}