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:
parent
c340829638
commit
5c1be71fa1
|
@ -14,98 +14,90 @@ const formatText = text => text.replace(
|
||||||
(match, url, title) => `[${ title }](${ url })`
|
(match, url, title) => `[${ title }](${ url })`
|
||||||
);
|
);
|
||||||
|
|
||||||
export default class Markdown extends React.Component {
|
const Markdown = React.memo(({
|
||||||
shouldComponentUpdate(nextProps) {
|
msg, customEmojis, style, rules, baseUrl, username, edited, numberOfLines
|
||||||
const { msg } = this.props;
|
}) => {
|
||||||
return nextProps.msg !== msg;
|
if (!msg) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
let m = formatText(msg);
|
||||||
render() {
|
if (m) {
|
||||||
const {
|
m = emojify(m, { output: 'unicode' });
|
||||||
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}>
|
|
||||||
{content}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
hashtag: node => (
|
|
||||||
<Text key={node.key} style={styles.mention}>
|
|
||||||
#{node.content}
|
|
||||||
</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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
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}>
|
||||||
|
{content}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
hashtag: node => (
|
||||||
|
<Text key={node.key} style={styles.mention}>
|
||||||
|
#{node.content}
|
||||||
|
</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 = {
|
Markdown.propTypes = {
|
||||||
msg: PropTypes.string,
|
msg: PropTypes.string,
|
||||||
|
@ -117,3 +109,5 @@ Markdown.propTypes = {
|
||||||
edited: PropTypes.bool,
|
edited: PropTypes.bool,
|
||||||
numberOfLines: PropTypes.number
|
numberOfLines: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Markdown;
|
||||||
|
|
|
@ -1,39 +1,83 @@
|
||||||
import { InteractionManager } from 'react-native';
|
import { InteractionManager } from 'react-native';
|
||||||
|
import semver from 'semver';
|
||||||
|
|
||||||
import reduxStore from '../createStore';
|
import reduxStore from '../createStore';
|
||||||
import database from '../realm';
|
import database from '../realm';
|
||||||
import * as actions from '../../actions';
|
import * as actions from '../../actions';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
|
|
||||||
const getLastMessage = () => {
|
const getUpdatedSince = () => {
|
||||||
const setting = database.objects('customEmojis').sorted('_updatedAt', true)[0];
|
const emoji = database.objects('customEmojis').sorted('_updatedAt', true)[0];
|
||||||
return setting && setting._updatedAt;
|
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() {
|
export default async function() {
|
||||||
try {
|
try {
|
||||||
const lastMessage = getLastMessage();
|
const serverVersion = reduxStore.getState().server.version;
|
||||||
// RC 0.61.0
|
const updatedSince = getUpdatedSince();
|
||||||
const result = await this.sdk.get('emoji-custom');
|
|
||||||
let { emojis } = result;
|
// if server version is lower than 0.75.0, fetches from old api
|
||||||
emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage);
|
if (semver.lt(serverVersion, '0.75.0')) {
|
||||||
if (emojis.length === 0) {
|
// RC 0.61.0
|
||||||
return;
|
const result = await this.sdk.get('emoji-custom');
|
||||||
}
|
|
||||||
emojis = this._prepareEmojis(emojis);
|
InteractionManager.runAfterInteractions(() => {
|
||||||
InteractionManager.runAfterInteractions(() => {
|
let { emojis } = result;
|
||||||
database.write(() => {
|
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
|
||||||
emojis.forEach((emoji) => {
|
database.write(() => {
|
||||||
try {
|
create(emojis);
|
||||||
database.create('customEmojis', emoji, true);
|
|
||||||
} catch (e) {
|
|
||||||
log('create custom emojis', e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(result.emojis)));
|
||||||
});
|
});
|
||||||
});
|
} else {
|
||||||
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis)));
|
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) {
|
} catch (e) {
|
||||||
log('getCustomEmojis', e);
|
log('getCustomEmojis', e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ export const merge = (subscription, room) => {
|
||||||
subscription.archived = room.archived;
|
subscription.archived = room.archived;
|
||||||
subscription.joinCodeRequired = room.joinCodeRequired;
|
subscription.joinCodeRequired = room.joinCodeRequired;
|
||||||
subscription.broadcast = room.broadcast;
|
subscription.broadcast = room.broadcast;
|
||||||
|
if (!subscription.roles || !subscription.roles.length) {
|
||||||
|
subscription.roles = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (room.muted && room.muted.length) {
|
if (room.muted && room.muted.length) {
|
||||||
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
||||||
|
|
|
@ -286,21 +286,13 @@ const frequentlyUsedEmojiSchema = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const customEmojiAliasesSchema = {
|
|
||||||
name: 'customEmojiAliases',
|
|
||||||
primaryKey: 'value',
|
|
||||||
properties: {
|
|
||||||
value: 'string'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const customEmojisSchema = {
|
const customEmojisSchema = {
|
||||||
name: 'customEmojis',
|
name: 'customEmojis',
|
||||||
primaryKey: '_id',
|
primaryKey: '_id',
|
||||||
properties: {
|
properties: {
|
||||||
_id: 'string',
|
_id: 'string',
|
||||||
name: 'string',
|
name: 'string',
|
||||||
aliases: { type: 'list', objectType: 'customEmojiAliases' },
|
aliases: 'string[]',
|
||||||
extension: 'string',
|
extension: 'string',
|
||||||
_updatedAt: { type: 'date', optional: true }
|
_updatedAt: { type: 'date', optional: true }
|
||||||
}
|
}
|
||||||
|
@ -353,7 +345,6 @@ const schema = [
|
||||||
permissionsSchema,
|
permissionsSchema,
|
||||||
url,
|
url,
|
||||||
frequentlyUsedEmojiSchema,
|
frequentlyUsedEmojiSchema,
|
||||||
customEmojiAliasesSchema,
|
|
||||||
customEmojisSchema,
|
customEmojisSchema,
|
||||||
messagesReactionsSchema,
|
messagesReactionsSchema,
|
||||||
messagesReactionsUsernamesSchema,
|
messagesReactionsUsernamesSchema,
|
||||||
|
@ -428,7 +419,7 @@ class DB {
|
||||||
return this.databases.activeDB = new Realm({
|
return this.databases.activeDB = new Realm({
|
||||||
path: `${ path }.realm`,
|
path: `${ path }.realm`,
|
||||||
schema,
|
schema,
|
||||||
schemaVersion: 8,
|
schemaVersion: 9,
|
||||||
migration: (oldRealm, newRealm) => {
|
migration: (oldRealm, newRealm) => {
|
||||||
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 8) {
|
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 8) {
|
||||||
const newSubs = newRealm.objects('subscriptions');
|
const newSubs = newRealm.objects('subscriptions');
|
||||||
|
@ -445,6 +436,14 @@ class DB {
|
||||||
const newThreadMessages = newRealm.objects('threadMessages');
|
const newThreadMessages = newRealm.objects('threadMessages');
|
||||||
newRealm.delete(newThreadMessages);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue