[FIX] Read only channel/broadcast (#1951)
* [FIX] Read only channel/broadcast * [FIX] Roles missing * [FIX] Check roles to readOnly * [FIX] Can post * [FIX] Respect post-readonly permission * [FIX] Search a room readOnly Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
1427e530bf
commit
404c381ca2
|
@ -79,7 +79,8 @@ class DB {
|
||||||
Message,
|
Message,
|
||||||
Thread,
|
Thread,
|
||||||
ThreadMessage,
|
ThreadMessage,
|
||||||
Upload
|
Upload,
|
||||||
|
Permission
|
||||||
],
|
],
|
||||||
actionsEnabled: true
|
actionsEnabled: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -72,6 +72,7 @@ const createOrUpdateSubscription = async(subscription, room) => {
|
||||||
autoTranslate: s.autoTranslate,
|
autoTranslate: s.autoTranslate,
|
||||||
autoTranslateLanguage: s.autoTranslateLanguage,
|
autoTranslateLanguage: s.autoTranslateLanguage,
|
||||||
lastMessage: s.lastMessage,
|
lastMessage: s.lastMessage,
|
||||||
|
roles: s.roles,
|
||||||
usernames: s.usernames,
|
usernames: s.usernames,
|
||||||
uids: s.uids
|
uids: s.uids
|
||||||
};
|
};
|
||||||
|
|
|
@ -289,14 +289,11 @@ const RocketChat = {
|
||||||
user = {
|
user = {
|
||||||
id: userRecord.id,
|
id: userRecord.id,
|
||||||
token: userRecord.token,
|
token: userRecord.token,
|
||||||
username: userRecord.username
|
username: userRecord.username,
|
||||||
|
roles: userRecord.roles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
reduxStore.dispatch(shareSetUser({
|
reduxStore.dispatch(shareSetUser(user));
|
||||||
id: user.id,
|
|
||||||
token: user.token,
|
|
||||||
username: user.username
|
|
||||||
}));
|
|
||||||
await RocketChat.login({ resume: user.token });
|
await RocketChat.login({ resume: user.token });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
|
@ -308,6 +305,8 @@ const RocketChat = {
|
||||||
this.shareSDK = null;
|
this.shareSDK = null;
|
||||||
}
|
}
|
||||||
database.share = null;
|
database.share = null;
|
||||||
|
|
||||||
|
reduxStore.dispatch(shareSetUser(null));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateJitsiTimeout(rid) {
|
updateJitsiTimeout(rid) {
|
||||||
|
@ -580,6 +579,19 @@ const RocketChat = {
|
||||||
}
|
}
|
||||||
data = data.slice(0, 7);
|
data = data.slice(0, 7);
|
||||||
|
|
||||||
|
data = data.map((sub) => {
|
||||||
|
if (sub.t !== 'd') {
|
||||||
|
return ({
|
||||||
|
rid: sub.rid,
|
||||||
|
name: sub.name,
|
||||||
|
fname: sub.fname,
|
||||||
|
t: sub.t,
|
||||||
|
search: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return sub;
|
||||||
|
});
|
||||||
|
|
||||||
const usernames = data.map(sub => sub.name);
|
const usernames = data.map(sub => sub.name);
|
||||||
try {
|
try {
|
||||||
if (data.length < 7) {
|
if (data.length < 7) {
|
||||||
|
@ -951,7 +963,7 @@ const RocketChat = {
|
||||||
// get the room from database
|
// get the room from database
|
||||||
const room = await subsCollection.find(rid);
|
const room = await subsCollection.find(rid);
|
||||||
// get room roles
|
// get room roles
|
||||||
roomRoles = room.roles;
|
roomRoles = room.roles || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('hasPermission -> Room not found');
|
console.log('hasPermission -> Room not found');
|
||||||
return permissions.reduce((result, permission) => {
|
return permissions.reduce((result, permission) => {
|
||||||
|
@ -962,8 +974,10 @@ const RocketChat = {
|
||||||
// get permissions from database
|
// get permissions from database
|
||||||
try {
|
try {
|
||||||
const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch();
|
const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch();
|
||||||
|
const shareUser = reduxStore.getState().share.user;
|
||||||
|
const loginUser = reduxStore.getState().login.user;
|
||||||
// get user roles on the server from redux
|
// get user roles on the server from redux
|
||||||
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
|
const userRoles = (shareUser.roles || loginUser.roles) || [];
|
||||||
// merge both roles
|
// merge both roles
|
||||||
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
|
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
|
||||||
export const isOwner = room => room && room.roles && room.roles.length && !!room.roles.find(role => role === 'owner');
|
export const canPost = async({ rid }) => {
|
||||||
|
try {
|
||||||
|
const permission = await RocketChat.hasPermission(['post-readonly'], rid);
|
||||||
|
return permission && permission['post-readonly'];
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
|
export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
|
||||||
|
|
||||||
export const isReadOnly = (room, user) => {
|
export const isReadOnly = async(room, user) => {
|
||||||
if (isOwner(room)) {
|
if (room.archived) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const allowPost = await canPost(room);
|
||||||
|
if (allowPost) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (room && room.ro) || isMuted(room, user);
|
return (room && room.ro) || isMuted(room, user);
|
||||||
|
|
|
@ -125,10 +125,14 @@ class DirectoryView extends React.Component {
|
||||||
this.setState(({ showOptionsDropdown }) => ({ showOptionsDropdown: !showOptionsDropdown }));
|
this.setState(({ showOptionsDropdown }) => ({ showOptionsDropdown: !showOptionsDropdown }));
|
||||||
}
|
}
|
||||||
|
|
||||||
goRoom = async({ rid, name, t }) => {
|
goRoom = async({
|
||||||
|
rid, name, t, search
|
||||||
|
}) => {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
await navigation.navigate('RoomsListView');
|
await navigation.navigate('RoomsListView');
|
||||||
navigation.navigate('RoomView', { rid, name, t });
|
navigation.navigate('RoomView', {
|
||||||
|
rid, name, t, search
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressItem = async(item) => {
|
onPressItem = async(item) => {
|
||||||
|
@ -139,7 +143,9 @@ class DirectoryView extends React.Component {
|
||||||
this.goRoom({ rid: result.room._id, name: item.username, t: 'd' });
|
this.goRoom({ rid: result.room._id, name: item.username, t: 'd' });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.goRoom({ rid: item._id, name: item.name, t: 'c' });
|
this.goRoom({
|
||||||
|
rid: item._id, name: item.name, t: 'c', search: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,10 @@ const stateAttrsUpdate = [
|
||||||
'editing',
|
'editing',
|
||||||
'replying',
|
'replying',
|
||||||
'reacting',
|
'reacting',
|
||||||
|
'readOnly',
|
||||||
'member'
|
'member'
|
||||||
];
|
];
|
||||||
const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname'];
|
const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname', 'roles'];
|
||||||
|
|
||||||
class RoomView extends React.Component {
|
class RoomView extends React.Component {
|
||||||
static navigationOptions = ({ navigation, screenProps }) => {
|
static navigationOptions = ({ navigation, screenProps }) => {
|
||||||
|
@ -164,6 +165,7 @@ class RoomView extends React.Component {
|
||||||
const selectedMessage = props.navigation.getParam('message');
|
const selectedMessage = props.navigation.getParam('message');
|
||||||
const name = props.navigation.getParam('name');
|
const name = props.navigation.getParam('name');
|
||||||
const fname = props.navigation.getParam('fname');
|
const fname = props.navigation.getParam('fname');
|
||||||
|
const search = props.navigation.getParam('search');
|
||||||
const prid = props.navigation.getParam('prid');
|
const prid = props.navigation.getParam('prid');
|
||||||
this.state = {
|
this.state = {
|
||||||
joined: true,
|
joined: true,
|
||||||
|
@ -183,7 +185,7 @@ class RoomView extends React.Component {
|
||||||
replying: !!selectedMessage,
|
replying: !!selectedMessage,
|
||||||
replyWithMention: false,
|
replyWithMention: false,
|
||||||
reacting: false,
|
reacting: false,
|
||||||
announcement: null
|
readOnly: false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (room && room.observe) {
|
if (room && room.observe) {
|
||||||
|
@ -192,6 +194,12 @@ class RoomView extends React.Component {
|
||||||
this.findAndObserveRoom(this.rid);
|
this.findAndObserveRoom(this.rid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setReadOnly();
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
this.updateRoom();
|
||||||
|
}
|
||||||
|
|
||||||
this.messagebox = React.createRef();
|
this.messagebox = React.createRef();
|
||||||
this.list = React.createRef();
|
this.list = React.createRef();
|
||||||
this.mounted = false;
|
this.mounted = false;
|
||||||
|
@ -278,6 +286,9 @@ class RoomView extends React.Component {
|
||||||
if (roomUpdate.topic !== prevState.roomUpdate.topic) {
|
if (roomUpdate.topic !== prevState.roomUpdate.topic) {
|
||||||
navigation.setParams({ subtitle: roomUpdate.topic });
|
navigation.setParams({ subtitle: roomUpdate.topic });
|
||||||
}
|
}
|
||||||
|
if (!isEqual(prevState.roomUpdate.roles, roomUpdate.roles)) {
|
||||||
|
this.setReadOnly();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) {
|
if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) {
|
||||||
navigation.setParams({ name: this.getRoomTitle(room) });
|
navigation.setParams({ name: this.getRoomTitle(room) });
|
||||||
|
@ -346,6 +357,32 @@ class RoomView extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setReadOnly = async() => {
|
||||||
|
const { room } = this.state;
|
||||||
|
const { user } = this.props;
|
||||||
|
const readOnly = await isReadOnly(room, user);
|
||||||
|
this.setState({ readOnly });
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRoom = async() => {
|
||||||
|
const db = database.active;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const subCollection = db.collections.get('subscriptions');
|
||||||
|
const sub = await subCollection.find(this.rid);
|
||||||
|
|
||||||
|
const { room } = await RocketChat.getRoomInfo(this.rid);
|
||||||
|
|
||||||
|
await db.action(async() => {
|
||||||
|
await sub.update((s) => {
|
||||||
|
Object.assign(s, room);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init = async() => {
|
init = async() => {
|
||||||
try {
|
try {
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
@ -762,12 +799,6 @@ class RoomView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isReadOnly() {
|
|
||||||
const { room } = this.state;
|
|
||||||
const { user } = this.props;
|
|
||||||
return isReadOnly(room, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
blockAction = ({
|
blockAction = ({
|
||||||
actionId, appId, value, blockId, rid, mid
|
actionId, appId, value, blockId, rid, mid
|
||||||
}) => RocketChat.triggerBlockAction({
|
}) => RocketChat.triggerBlockAction({
|
||||||
|
@ -855,7 +886,7 @@ class RoomView extends React.Component {
|
||||||
|
|
||||||
renderFooter = () => {
|
renderFooter = () => {
|
||||||
const {
|
const {
|
||||||
joined, room, selectedMessage, editing, replying, replyWithMention
|
joined, room, selectedMessage, editing, replying, replyWithMention, readOnly
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { navigation, theme } = this.props;
|
const { navigation, theme } = this.props;
|
||||||
|
|
||||||
|
@ -876,7 +907,7 @@ class RoomView extends React.Component {
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.isReadOnly || room.archived) {
|
if (readOnly) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.readOnly}>
|
<View style={styles.readOnly}>
|
||||||
<Text style={[styles.previewMode, { color: themes[theme].titleText }]} accessibilityLabel={I18n.t('This_room_is_read_only')}>{I18n.t('This_room_is_read_only')}</Text>
|
<Text style={[styles.previewMode, { color: themes[theme].titleText }]} accessibilityLabel={I18n.t('This_room_is_read_only')}>{I18n.t('This_room_is_read_only')}</Text>
|
||||||
|
@ -914,7 +945,7 @@ class RoomView extends React.Component {
|
||||||
|
|
||||||
renderActions = () => {
|
renderActions = () => {
|
||||||
const {
|
const {
|
||||||
room, selectedMessage, showActions, showErrorActions, joined
|
room, selectedMessage, showActions, showErrorActions, joined, readOnly
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const {
|
const {
|
||||||
user, navigation
|
user, navigation
|
||||||
|
@ -935,7 +966,7 @@ class RoomView extends React.Component {
|
||||||
editInit={this.onEditInit}
|
editInit={this.onEditInit}
|
||||||
replyInit={this.onReplyInit}
|
replyInit={this.onReplyInit}
|
||||||
reactionInit={this.onReactionInit}
|
reactionInit={this.onReactionInit}
|
||||||
isReadOnly={this.isReadOnly}
|
isReadOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
|
|
|
@ -542,8 +542,9 @@ class RoomsListView extends React.Component {
|
||||||
name: this.getRoomTitle(item),
|
name: this.getRoomTitle(item),
|
||||||
t: item.t,
|
t: item.t,
|
||||||
prid: item.prid,
|
prid: item.prid,
|
||||||
roomUserId: this.getUidDirectMessage(item),
|
room: item,
|
||||||
room: item
|
search: item.search,
|
||||||
|
roomUserId: this.getUidDirectMessage(item)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,18 +69,29 @@ class ShareView extends React.Component {
|
||||||
fileInfo,
|
fileInfo,
|
||||||
room,
|
room,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
readOnly: false,
|
||||||
file: {
|
file: {
|
||||||
name: fileInfo ? fileInfo.name : '',
|
name: fileInfo ? fileInfo.name : '',
|
||||||
description: ''
|
description: ''
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.setReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
navigation.setParams({ sendMessage: this._sendMessage });
|
||||||
|
}
|
||||||
|
|
||||||
|
setReadOnly = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
const { navigation, user } = this.props;
|
const { navigation, user } = this.props;
|
||||||
const { username } = user;
|
const { username } = user;
|
||||||
navigation.setParams({ sendMessage: this._sendMessage, canSend: !(isReadOnly(room, { username }) || isBlocked(room)) });
|
const readOnly = await isReadOnly(room, { username });
|
||||||
|
|
||||||
|
this.setState({ readOnly });
|
||||||
|
navigation.setParams({ canSend: !(readOnly || isBlocked(room)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesToSize = bytes => `${ (bytes / 1048576).toFixed(2) }MB`;
|
bytesToSize = bytes => `${ (bytes / 1048576).toFixed(2) }MB`;
|
||||||
|
@ -237,8 +248,9 @@ class ShareView extends React.Component {
|
||||||
|
|
||||||
renderError = () => {
|
renderError = () => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, styles.centered]}>
|
<View style={[styles.container, styles.centered, { backgroundColor: themes[theme].backgroundColor }]}>
|
||||||
<Text style={styles.title}>
|
<Text style={styles.title}>
|
||||||
{
|
{
|
||||||
isBlocked(room) ? I18n.t('This_room_is_blocked') : I18n.t('This_room_is_read_only')
|
isBlocked(room) ? I18n.t('This_room_is_blocked') : I18n.t('This_room_is_read_only')
|
||||||
|
@ -249,13 +261,12 @@ class ShareView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { user, theme } = this.props;
|
const { theme } = this.props;
|
||||||
const { username } = user;
|
|
||||||
const {
|
const {
|
||||||
name, loading, isMedia, room
|
name, loading, isMedia, room, readOnly
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
if (isReadOnly(room, { username }) || isBlocked(room)) {
|
if (readOnly || isBlocked(room)) {
|
||||||
return this.renderError();
|
return this.renderError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue