Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Broadcast channels #301

Merged
merged 31 commits into from
May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f91e7e8
first test
ggazzo Apr 25, 2018
446090c
welcome , add server and create user e2e
ggazzo Apr 26, 2018
32974a6
eslint ignore
ggazzo Apr 26, 2018
f0a5909
Public tests
diegolmello May 3, 2018
07e8416
CircleCI setup
diegolmello May 4, 2018
98529d8
Refactor
diegolmello May 4, 2018
d27d37d
RoomsListView tests
diegolmello May 7, 2018
47c5230
RoomView tests
diegolmello May 8, 2018
3e2e66f
RoomActionsView
diegolmello May 9, 2018
3d838f2
Tests done
diegolmello May 9, 2018
86eebe4
Bug fixes
diegolmello May 10, 2018
53c93f8
Performance improvements
diegolmello May 10, 2018
a23270e
Create channel bug fix
diegolmello May 14, 2018
4659f68
Fixed erase/leave room unsubscribe error
diegolmello May 14, 2018
c9d140b
Tests fixed
diegolmello May 14, 2018
56cd398
Tap room member and go to the room
diegolmello May 14, 2018
a442b42
Tests
diegolmello May 14, 2018
a587633
Add server fixed
diegolmello May 15, 2018
ca1e5f2
Minor fixes
diegolmello May 15, 2018
8147cb6
DDP fix
diegolmello May 18, 2018
19ff437
Tests
diegolmello May 18, 2018
fff39f8
User presence tests
diegolmello May 21, 2018
e594103
User creation tests
diegolmello May 21, 2018
cfbed34
Change server tests
diegolmello May 21, 2018
50f9e22
Tests fixed
diegolmello May 21, 2018
0fb2cf0
Merge branch 'develop' into detox
diegolmello May 21, 2018
90e3485
Remove imports
diegolmello May 22, 2018
0c3399a
Readme updated
diegolmello May 22, 2018
fceee1a
Broadcast channels
diegolmello May 22, 2018
e60e1d3
Merge branch 'develop' into broadcast
diegolmello May 23, 2018
7ef658f
e2e tests
diegolmello May 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/actions/actionsTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export const MESSAGES = createRequestTypes('MESSAGES', [
'TOGGLE_PIN_FAILURE',
'SET_INPUT',
'CLEAR_INPUT',
'TOGGLE_REACTION_PICKER'
'TOGGLE_REACTION_PICKER',
'REPLY_BROADCAST'
]);
export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]);
export const SELECTED_USERS = createRequestTypes('SELECTED_USERS', ['ADD_USER', 'REMOVE_USER', 'RESET', 'SET_LOADING']);
Expand Down
7 changes: 7 additions & 0 deletions app/actions/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,10 @@ export function toggleReactionPicker(message) {
message
};
}

export function replyBroadcast(message) {
return {
type: types.MESSAGES.REPLY_BROADCAST,
message
};
}
6 changes: 5 additions & 1 deletion app/containers/RoomTypeIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const styles = StyleSheet.create({
});

const RoomTypeIcon = ({ type, size }) => {
if (!type) {
return null;
}

const icon = {
c: 'pound',
p: 'lock',
Expand All @@ -21,7 +25,7 @@ const RoomTypeIcon = ({ type, size }) => {
};

RoomTypeIcon.propTypes = {
type: PropTypes.string.isRequired,
type: PropTypes.string,
size: PropTypes.number
};

Expand Down
70 changes: 48 additions & 22 deletions app/containers/message/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,28 @@ import Reply from './Reply';
import ReactionsModal from './ReactionsModal';
import Emoji from './Emoji';
import styles from './styles';
import { actionsShow, errorActionsShow, toggleReactionPicker } from '../../actions/messages';
import { actionsShow, errorActionsShow, toggleReactionPicker, replyBroadcast } from '../../actions/messages';
import messagesStatus from '../../constants/messagesStatus';
import Touch from '../../utils/touch';

const SYSTEM_MESSAGES = [
'r',
'au',
'ru',
'ul',
'uj',
'rm',
'user-muted',
'user-unmuted',
'message_pinned',
'subscription-role-added',
'subscription-role-removed',
'room_changed_description',
'room_changed_announcement',
'room_changed_topic',
'room_changed_privacy'
];

const getInfoMessage = ({
t, role, msg, u
}) => {
Expand Down Expand Up @@ -68,7 +86,8 @@ const getInfoMessage = ({
}), dispatch => ({
actionsShow: actionMessage => dispatch(actionsShow(actionMessage)),
errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage)),
toggleReactionPicker: message => dispatch(toggleReactionPicker(message))
toggleReactionPicker: message => dispatch(toggleReactionPicker(message)),
replyBroadcast: message => dispatch(replyBroadcast(message))
}))
export default class Message extends React.Component {
static propTypes = {
Expand All @@ -83,17 +102,20 @@ export default class Message extends React.Component {
editing: PropTypes.bool,
errorActionsShow: PropTypes.func,
toggleReactionPicker: PropTypes.func,
replyBroadcast: PropTypes.func,
onReactionPress: PropTypes.func,
style: ViewPropTypes.style,
onLongPress: PropTypes.func,
_updatedAt: PropTypes.instanceOf(Date),
archived: PropTypes.bool
archived: PropTypes.bool,
broadcast: PropTypes.bool
}

static defaultProps = {
onLongPress: () => {},
_updatedAt: new Date(),
archived: false
archived: false,
broadcast: false
}

constructor(props) {
Expand All @@ -116,6 +138,9 @@ export default class Message extends React.Component {
if (!equal(this.props.reactions, nextProps.reactions)) {
return true;
}
if (this.props.broadcast !== nextProps.broadcast) {
return true;
}
return this.props._updatedAt.toGMTString() !== nextProps._updatedAt.toGMTString();
}

Expand Down Expand Up @@ -150,25 +175,11 @@ export default class Message extends React.Component {
parseMessage = () => JSON.parse(JSON.stringify(this.props.item));

isInfoMessage() {
return [
'r',
'au',
'ru',
'ul',
'uj',
'rm',
'user-muted',
'user-unmuted',
'message_pinned',
'subscription-role-added',
'subscription-role-removed',
'room_changed_description',
'room_changed_announcement',
'room_changed_topic',
'room_changed_privacy'
].includes(this.props.item.t);
return SYSTEM_MESSAGES.includes(this.props.item.t);
}

isOwn = () => this.props.item.u && this.props.item.u._id === this.props.user.id;

isDeleted() {
return this.props.item.t === 'rm';
}
Expand All @@ -187,7 +198,7 @@ export default class Message extends React.Component {
if (previousItem && (
(previousItem.ts.toDateString() === item.ts.toDateString()) &&
(previousItem.u.username === item.u.username) &&
!(previousItem.groupable === false || item.groupable === false) &&
!(previousItem.groupable === false || item.groupable === false || this.props.broadcast === true) &&
(previousItem.status === item.status) &&
(item.ts - previousItem.ts < this.props.Message_GroupingPeriod * 1000)
)) {
Expand Down Expand Up @@ -303,6 +314,20 @@ export default class Message extends React.Component {
);
}

renderBroadcastReply() {
if (!this.props.broadcast || this.isOwn()) {
return null;
}
return (
<TouchableOpacity
style={styles.broadcastButton}
onPress={() => this.props.replyBroadcast(this.parseMessage())}
>
<Text style={styles.broadcastButtonText}>Reply</Text>
</TouchableOpacity>
);
}

render() {
const {
item, message, editing, style, archived
Expand All @@ -329,6 +354,7 @@ export default class Message extends React.Component {
{this.renderAttachment()}
{this.renderUrl()}
{this.renderReactions()}
{this.renderBroadcastReply()}
</View>
</View>
{this.state.reactionsModal &&
Expand Down
13 changes: 13 additions & 0 deletions app/containers/message/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,18 @@ export default StyleSheet.create({
padding: 10,
paddingRight: 12,
paddingLeft: 0
},
broadcastButton: {
borderColor: '#1d74f5',
borderWidth: 2,
borderRadius: 2,
paddingVertical: 10,
width: 100,
alignItems: 'center',
justifyContent: 'center',
marginTop: 6
},
broadcastButtonText: {
color: '#1d74f5'
}
});
7 changes: 6 additions & 1 deletion app/lib/methods/helpers/mergeSubscriptionsRooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import normalizeMessage from './normalizeMessage';
export const merge = (subscription, room) => {
subscription.muted = [];
if (room) {
if (room.rid) {
subscription.rid = room.rid;
}
subscription.roomUpdatedAt = room._updatedAt;
subscription.lastMessage = normalizeMessage(room.lastMessage);
subscription.ro = room.ro;
Expand All @@ -13,6 +16,7 @@ export const merge = (subscription, room) => {
subscription.reactWhenReadOnly = room.reactWhenReadOnly;
subscription.archived = room.archived;
subscription.joinCodeRequired = room.joinCodeRequired;
subscription.broadcast = room.broadcast;

if (room.muted && room.muted.length) {
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
Expand All @@ -28,7 +32,8 @@ export const merge = (subscription, room) => {
subscription.notifications = false;
}

subscription.blocked = !!subscription.blocker;
subscription.blocker = !!subscription.blocker;
subscription.blocked = !!subscription.blocked;
return subscription;
};

Expand Down
20 changes: 14 additions & 6 deletions app/lib/methods/subscriptions/rooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,24 @@ export default async function subscribeRooms(id) {
const [type, data] = ddpMessage.fields.args;
const [, ev] = ddpMessage.fields.eventName.split('/');
if (/subscriptions/.test(ev)) {
const tpm = merge(data);
const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
const tpm = merge(data, rooms[0]);
database.write(() => {
database.create('subscriptions', tpm, true);
database.delete(rooms);
});
}
if (/rooms/.test(ev) && type === 'updated') {
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
database.write(() => {
merge(sub, data);
});
if (/rooms/.test(ev)) {
if (type === 'updated') {
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
database.write(() => {
merge(sub, data);
});
} else if (type === 'inserted') {
database.write(() => {
database.create('rooms', data, true);
});
}
}
if (/message/.test(ev)) {
const [args] = ddpMessage.fields.args;
Expand Down
9 changes: 4 additions & 5 deletions app/lib/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@ const roomsSchema = {
primaryKey: '_id',
properties: {
_id: 'string',
t: 'string',
lastMessage: 'messages',
description: { type: 'string', optional: true },
_updatedAt: { type: 'date', optional: true }
broadcast: { type: 'bool', optional: true }
}
};

Expand Down Expand Up @@ -97,11 +94,13 @@ const subscriptionSchema = {
announcement: { type: 'string', optional: true },
topic: { type: 'string', optional: true },
blocked: { type: 'bool', optional: true },
blocker: { type: 'bool', optional: true },
reactWhenReadOnly: { type: 'bool', optional: true },
archived: { type: 'bool', optional: true },
joinCodeRequired: { type: 'bool', optional: true },
notifications: { type: 'bool', optional: true },
muted: { type: 'list', objectType: 'usersMuted' }
muted: { type: 'list', objectType: 'usersMuted' },
broadcast: { type: 'bool', optional: true }
}
};

Expand Down
6 changes: 4 additions & 2 deletions app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ const RocketChat = {
subscribeRooms,
subscribeRoom,
canOpenRoom,
createChannel({ name, users, type }) {
return call(type ? 'createChannel' : 'createPrivateGroup', name, users, type);
createChannel({
name, users, type, readOnly, broadcast
}) {
return call(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast });
},
async createDirectMessageAndWait(username) {
const room = await RocketChat.createDirectMessage(username);
Expand Down
29 changes: 27 additions & 2 deletions app/sagas/messages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { takeLatest, put, call } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import { takeLatest, put, call, select } from 'redux-saga/effects';
import { MESSAGES } from '../actions/actionsTypes';
import {
messagesSuccess,
Expand All @@ -12,9 +13,13 @@ import {
permalinkSuccess,
permalinkFailure,
togglePinSuccess,
togglePinFailure
togglePinFailure,
setInput
} from '../actions/messages';
import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
import { goRoom } from '../containers/routes/NavigationService';
import log from '../utils/log';

const deleteMessage = message => RocketChat.deleteMessage(message);
const editMessage = message => RocketChat.editMessage(message);
Expand Down Expand Up @@ -81,12 +86,32 @@ const handleTogglePinRequest = function* handleTogglePinRequest({ message }) {
}
};

const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
try {
const { username } = message.u;
const subscriptions = database.objects('subscriptions').filtered('name = $0', username);
if (subscriptions.length) {
goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name });
} else {
const room = yield RocketChat.createDirectMessage(username);
goRoom({ rid: room.rid, name: username });
}
yield delay(100);
const server = yield select(state => state.server.server);
const msg = `[ ](${ server }/direct/${ username }?msg=${ message._id })`;
yield put(setInput({ msg }));
} catch (e) {
log('handleReplyBroadcast', e);
}
};

const root = function* root() {
yield takeLatest(MESSAGES.REQUEST, get);
yield takeLatest(MESSAGES.DELETE_REQUEST, handleDeleteRequest);
yield takeLatest(MESSAGES.EDIT_REQUEST, handleEditRequest);
yield takeLatest(MESSAGES.TOGGLE_STAR_REQUEST, handleToggleStarRequest);
yield takeLatest(MESSAGES.PERMALINK_REQUEST, handlePermalinkRequest);
yield takeLatest(MESSAGES.TOGGLE_PIN_REQUEST, handleTogglePinRequest);
yield takeLatest(MESSAGES.REPLY_BROADCAST, handleReplyBroadcast);
};
export default root;
Loading