Skip to content

Commit

Permalink
Update custom emojis endpoint (#852)
Browse files Browse the repository at this point in the history
* Update emoji endpoint

* Use React.memo on Markdown

* Support RC versions lower than 0.75.0

* Realm migration
  • Loading branch information
diegolmello committed Apr 26, 2019
1 parent c340829 commit 5c1be71
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 123 deletions.
172 changes: 83 additions & 89 deletions app/containers/message/Markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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>
),
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>;
);
},
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 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>
);
}
}
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,
Expand All @@ -117,3 +109,5 @@ Markdown.propTypes = {
edited: PropTypes.bool,
numberOfLines: PropTypes.number
};

export default Markdown;
90 changes: 67 additions & 23 deletions app/lib/methods/getCustomEmojis.js
Original file line number Diff line number Diff line change
@@ -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);
}
Expand Down
3 changes: 3 additions & 0 deletions app/lib/methods/helpers/mergeSubscriptionsRooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }));
Expand Down
21 changes: 10 additions & 11 deletions app/lib/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down Expand Up @@ -353,7 +345,6 @@ const schema = [
permissionsSchema,
url,
frequentlyUsedEmojiSchema,
customEmojiAliasesSchema,
customEmojisSchema,
messagesReactionsSchema,
messagesReactionsUsernamesSchema,
Expand Down Expand Up @@ -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');
Expand All @@ -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);
}
}
});
}
Expand Down

0 comments on commit 5c1be71

Please sign in to comment.