Merge branch 'develop' into single-server

# Conflicts:
#	android/app/build.gradle
This commit is contained in:
Diego Mello 2020-04-13 16:35:42 -03:00
commit f872d8ae14
21 changed files with 192 additions and 81 deletions

View File

@ -48,6 +48,7 @@ const TwoFactor = React.memo(({ theme, split }) => {
useDeepCompareEffect(() => { useDeepCompareEffect(() => {
if (!_.isEmpty(data)) { if (!_.isEmpty(data)) {
setCode('');
setVisible(true); setVisible(true);
} else { } else {
setVisible(false); setVisible(false);
@ -94,7 +95,7 @@ const TwoFactor = React.memo(({ theme, split }) => {
<View style={styles.container}> <View style={styles.container}>
<View style={[styles.content, split && [sharedStyles.modal, sharedStyles.modalFormSheet], { backgroundColor: themes[theme].backgroundColor }]}> <View style={[styles.content, split && [sharedStyles.modal, sharedStyles.modalFormSheet], { backgroundColor: themes[theme].backgroundColor }]}>
<Text style={[styles.title, { color }]}>{I18n.t(method?.title || 'Two_Factor_Authentication')}</Text> <Text style={[styles.title, { color }]}>{I18n.t(method?.title || 'Two_Factor_Authentication')}</Text>
<Text style={[styles.subtitle, { color }]}>{I18n.t(method?.text)}</Text> {method?.text ? <Text style={[styles.subtitle, { color }]}>{I18n.t(method.text)}</Text> : null}
<TextInput <TextInput
value={code} value={code}
theme={theme} theme={theme}

View File

@ -15,11 +15,12 @@ export default StyleSheet.create({
}, },
title: { title: {
fontSize: 14, fontSize: 14,
paddingBottom: 8,
...sharedStyles.textBold ...sharedStyles.textBold
}, },
subtitle: { subtitle: {
fontSize: 14, fontSize: 14,
paddingVertical: 8, paddingBottom: 8,
...sharedStyles.textRegular, ...sharedStyles.textRegular,
...sharedStyles.textAlignCenter ...sharedStyles.textAlignCenter
}, },

View File

@ -6,8 +6,7 @@ const Blocks = React.memo(({
blocks, id: mid, rid, blockAction blocks, id: mid, rid, blockAction
}) => { }) => {
if (blocks && blocks.length > 0) { if (blocks && blocks.length > 0) {
const [, secondBlock] = blocks; const appId = blocks[0]?.appId || '';
const { appId = '' } = secondBlock;
return React.createElement( return React.createElement(
messageBlockWithContext({ messageBlockWithContext({
action: async({ actionId, value, blockId }) => { action: async({ actionId, value, blockId }) => {

View File

@ -80,7 +80,8 @@ class DB {
Message, Message,
Thread, Thread,
ThreadMessage, ThreadMessage,
Upload Upload,
Permission
], ],
actionsEnabled: true actionsEnabled: true
}); });

View File

@ -61,8 +61,15 @@ export default async function canOpenRoom({ rid, path }) {
if (rid) { if (rid) {
try { try {
await subsCollection.find(rid); const room = await subsCollection.find(rid);
return { rid }; return {
rid,
t: room.t,
name: room.name,
fname: room.fname,
prid: room.prid,
uids: room.uids
};
} catch (e) { } catch (e) {
// Do nothing // Do nothing
} }

View File

@ -13,6 +13,22 @@ import fetch from '../../utils/fetch';
const serverInfoKeys = ['Site_Name', 'UI_Use_Real_Name', 'FileUpload_MediaTypeWhiteList', 'FileUpload_MaxFileSize']; const serverInfoKeys = ['Site_Name', 'UI_Use_Real_Name', 'FileUpload_MediaTypeWhiteList', 'FileUpload_MaxFileSize'];
// these settings are used only on onboarding process
const loginSettings = [
'API_Gitlab_URL',
'CAS_enabled',
'CAS_login_url',
'Accounts_EmailVerification',
'Accounts_ManuallyApproveNewUsers',
'Accounts_ShowFormLogin',
'Site_Url',
'Accounts_RegistrationForm',
'Accounts_RegistrationForm_LinkReplacementText',
'Accounts_EmailOrUsernamePlaceholder',
'Accounts_PasswordPlaceholder',
'Accounts_PasswordReset'
];
const serverInfoUpdate = async(serverInfo, iconSetting) => { const serverInfoUpdate = async(serverInfo, iconSetting) => {
const serversDB = database.servers; const serversDB = database.servers;
const serverId = reduxStore.getState().server.server; const serverId = reduxStore.getState().server.server;
@ -54,7 +70,7 @@ const serverInfoUpdate = async(serverInfo, iconSetting) => {
export async function getLoginSettings({ server }) { export async function getLoginSettings({ server }) {
try { try {
const settingsParams = JSON.stringify(['Accounts_ShowFormLogin', 'Accounts_RegistrationForm']); const settingsParams = JSON.stringify(loginSettings);
const result = await fetch(`${ server }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json()); const result = await fetch(`${ server }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json());
if (result.success && result.settings.length) { if (result.success && result.settings.length) {
@ -84,7 +100,7 @@ export async function setSettings() {
export default async function() { export default async function() {
try { try {
const db = database.active; const db = database.active;
const settingsParams = JSON.stringify(Object.keys(settings)); const settingsParams = JSON.stringify(Object.keys(settings).filter(key => !loginSettings.includes(key)));
// RC 0.60.0 // RC 0.60.0
const result = await fetch(`${ this.sdk.client.host }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json()); const result = await fetch(`${ this.sdk.client.host }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json());

View File

@ -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
}; };

View File

@ -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) {
@ -338,8 +337,8 @@ const RocketChat = {
if (e.data?.error && (e.data.error === 'totp-required' || e.data.error === 'totp-invalid')) { if (e.data?.error && (e.data.error === 'totp-required' || e.data.error === 'totp-invalid')) {
const { details } = e.data; const { details } = e.data;
try { try {
await twoFactor({ method: details?.method, invalid: e.data.error === 'totp-invalid' }); const code = await twoFactor({ method: details?.method || 'totp', invalid: e.data.error === 'totp-invalid' });
return resolve(this.loginTOTP(params)); return resolve(this.loginTOTP({ ...params, code: code?.twoFactorCode }));
} catch { } catch {
// twoFactor was canceled // twoFactor was canceled
return reject(); return reject();
@ -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) {
@ -812,7 +824,9 @@ const RocketChat = {
return this.sdk.get('rooms.info', { roomId }); return this.sdk.get('rooms.info', { roomId });
}, },
getUidDirectMessage(room, userId) { getUidDirectMessage(room) {
const { id: userId } = reduxStore.getState().login.user;
// legacy method // legacy method
if (!room.uids && room.rid && room.t === 'd') { if (!room.uids && room.rid && room.t === 'd') {
return room.rid.replace(userId, '').trim(); return room.rid.replace(userId, '').trim();
@ -949,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) => {
@ -960,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])];

View File

@ -30,14 +30,21 @@ const handleInviteLink = function* handleInviteLink({ params, requireLogin = fal
const navigate = function* navigate({ params }) { const navigate = function* navigate({ params }) {
yield put(appStart('inside')); yield put(appStart('inside'));
if (params.path) { if (params.path) {
const room = yield RocketChat.canOpenRoom(params);
const [type, name] = params.path.split('/'); const [type, name] = params.path.split('/');
if (room) { if (type !== 'invite') {
yield Navigation.navigate('RoomsListView'); const room = yield RocketChat.canOpenRoom(params);
Navigation.navigate('RoomView', { name, t: roomTypes[type], ...room }); if (room) {
yield Navigation.navigate('RoomsListView');
Navigation.navigate('RoomView', {
name,
t: roomTypes[type],
roomUserId: RocketChat.getUidDirectMessage(room),
...room
});
}
} else {
yield handleInviteLink({ params });
} }
} else {
yield handleInviteLink({ params });
} }
}; };

View File

@ -12,8 +12,8 @@ import * as actions from '../actions';
import { import {
serverFailure, selectServerRequest, selectServerSuccess, selectServerFailure serverFailure, selectServerRequest, selectServerSuccess, selectServerFailure
} from '../actions/server'; } from '../actions/server';
import { setUser } from '../actions/login';
import { clearSettings } from '../actions/settings'; import { clearSettings } from '../actions/settings';
import { setUser } from '../actions/login';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import database from '../lib/database'; import database from '../lib/database';
import log, { logServerVersion } from '../utils/log'; import log, { logServerVersion } from '../utils/log';
@ -98,9 +98,8 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
const basicAuth = yield RNUserDefaults.get(`${ BASIC_AUTH_KEY }-${ server }`); const basicAuth = yield RNUserDefaults.get(`${ BASIC_AUTH_KEY }-${ server }`);
setBasicAuth(basicAuth); setBasicAuth(basicAuth);
yield put(clearSettings());
if (user) { if (user) {
yield put(clearSettings());
yield RocketChat.connect({ server, user, logoutOnError: true }); yield RocketChat.connect({ server, user, logoutOnError: true });
yield put(setUser(user)); yield put(setUser(user));
yield put(actions.appStart('inside')); yield put(actions.appStart('inside'));

24
app/utils/isReadOnly.js Normal file
View File

@ -0,0 +1,24 @@
import RocketChat from '../lib/rocketchat';
const canPost = async({ rid }) => {
try {
const permission = await RocketChat.hasPermission(['post-readonly'], rid);
return permission && permission['post-readonly'];
} catch {
// do nothing
}
return false;
};
const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
export const isReadOnly = async(room, user) => {
if (room.archived) {
return true;
}
const allowPost = await canPost(room);
if (allowPost) {
return false;
}
return (room && room.ro) || isMuted(room, user);
};

View File

@ -2,17 +2,6 @@ import moment from 'moment';
import I18n from '../i18n'; import I18n from '../i18n';
export const isOwner = room => room && room.roles && room.roles.length && !!room.roles.find(role => role === 'owner');
export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
export const isReadOnly = (room, user) => {
if (isOwner(room)) {
return false;
}
return (room && room.ro) || isMuted(room, user);
};
export const isBlocked = (room) => { export const isBlocked = (room) => {
if (room) { if (room) {
const { t, blocked, blocker } = room; const { t, blocked, blocker } = room;

View File

@ -80,7 +80,8 @@ class AuthenticationWebView extends React.PureComponent {
const { navigation } = this.props; const { navigation } = this.props;
const ssoToken = navigation.getParam('ssoToken'); const ssoToken = navigation.getParam('ssoToken');
const parsedUrl = parse(url, true); const parsedUrl = parse(url, true);
if (parsedUrl.pathname?.includes('ticket') || parsedUrl.pathname?.includes('validate') || parsedUrl.query?.saml_idp_credentialToken) { // ticket -> cas / validate & saml_idp_credentialToken -> saml
if (parsedUrl.pathname?.includes('validate') || parsedUrl.query?.ticket || parsedUrl.query?.saml_idp_credentialToken) {
let payload; let payload;
if (this.authType === 'saml') { if (this.authType === 'saml') {
const token = parsedUrl.query?.saml_idp_credentialToken || ssoToken; const token = parsedUrl.query?.saml_idp_credentialToken || ssoToken;

View File

@ -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
});
} }
} }

View File

@ -67,7 +67,7 @@ class ModalBlockView extends React.Component {
return { return {
title: textParser([title]), title: textParser([title]),
...themedHeader(theme), ...themedHeader(theme),
headerLeft: ( headerLeft: close ? (
<CustomHeaderButtons> <CustomHeaderButtons>
<Item <Item
title={textParser([close.text])} title={textParser([close.text])}
@ -76,8 +76,8 @@ class ModalBlockView extends React.Component {
testID='close-modal-uikit' testID='close-modal-uikit'
/> />
</CustomHeaderButtons> </CustomHeaderButtons>
), ) : null,
headerRight: ( headerRight: submit ? (
<CustomHeaderButtons> <CustomHeaderButtons>
<Item <Item
title={textParser([submit.text])} title={textParser([submit.text])}
@ -86,7 +86,7 @@ class ModalBlockView extends React.Component {
testID='submit-modal-uikit' testID='submit-modal-uikit'
/> />
</CustomHeaderButtons> </CustomHeaderButtons>
) ) : null
}; };
} }
@ -136,7 +136,7 @@ class ModalBlockView extends React.Component {
const { navigation } = this.props; const { navigation } = this.props;
const oldData = prevProps.navigation.getParam('data', {}); const oldData = prevProps.navigation.getParam('data', {});
const newData = navigation.getParam('data', {}); const newData = navigation.getParam('data', {});
if (!isEqual(oldData, newData)) { if (oldData.viewId !== newData.viewId) {
navigation.push('ModalBlockView', { data: newData }); navigation.push('ModalBlockView', { data: newData });
} }
} }
@ -148,12 +148,14 @@ class ModalBlockView extends React.Component {
} }
handleUpdate = ({ type, ...data }) => { handleUpdate = ({ type, ...data }) => {
const { navigation } = this.props;
if ([MODAL_ACTIONS.ERRORS].includes(type)) { if ([MODAL_ACTIONS.ERRORS].includes(type)) {
const { errors } = data; const { errors } = data;
this.setState({ errors }); this.setState({ errors });
} else { } else {
this.setState({ data }); this.setState({ data });
} }
navigation.setParams({ data });
}; };
cancel = async({ closeModal }) => { cancel = async({ closeModal }) => {

View File

@ -384,11 +384,10 @@ class RoomActionsView extends React.Component {
updateRoomMember = async() => { updateRoomMember = async() => {
const { room } = this.state; const { room } = this.state;
const { user } = this.props;
try { try {
if (!RocketChat.isGroupChat(room)) { if (!RocketChat.isGroupChat(room)) {
const roomUserId = RocketChat.getUidDirectMessage(room, user.id); const roomUserId = RocketChat.getUidDirectMessage(room);
const result = await RocketChat.getUserInfo(roomUserId); const result = await RocketChat.getUserInfo(roomUserId);
if (result.success) { if (result.success) {
this.setState({ member: result.user }); this.setState({ member: result.user });

View File

@ -34,7 +34,8 @@ import { themes } from '../../constants/colors';
import debounce from '../../utils/debounce'; import debounce from '../../utils/debounce';
import ReactionsModal from '../../containers/ReactionsModal'; import ReactionsModal from '../../containers/ReactionsModal';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import { isReadOnly, isBlocked } from '../../utils/room'; import { isBlocked } from '../../utils/room';
import { isReadOnly } from '../../utils/isReadOnly';
import { isIOS, isTablet } from '../../utils/deviceInfo'; import { isIOS, isTablet } from '../../utils/deviceInfo';
import { showErrorAlert } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
@ -65,9 +66,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 +166,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 +186,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 +195,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 +287,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 +358,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 });
@ -390,10 +428,10 @@ class RoomView extends React.Component {
const { t } = room; const { t } = room;
if (t === 'd' && !RocketChat.isGroupChat(room)) { if (t === 'd' && !RocketChat.isGroupChat(room)) {
const { user, navigation } = this.props; const { navigation } = this.props;
try { try {
const roomUserId = RocketChat.getUidDirectMessage(room, user.id); const roomUserId = RocketChat.getUidDirectMessage(room);
navigation.setParams({ roomUserId }); navigation.setParams({ roomUserId });
@ -762,12 +800,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 +887,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 +908,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 +946,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 +967,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

View File

@ -531,10 +531,7 @@ class RoomsListView extends React.Component {
getUserPresence = uid => RocketChat.getUserPresence(uid) getUserPresence = uid => RocketChat.getUserPresence(uid)
getUidDirectMessage = (room) => { getUidDirectMessage = room => RocketChat.getUidDirectMessage(room);
const { user: { id } } = this.props;
return RocketChat.getUidDirectMessage(room, id);
}
goRoom = (item) => { goRoom = (item) => {
const { navigation } = this.props; const { navigation } = this.props;
@ -545,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)
}); });
} }

View File

@ -13,7 +13,8 @@ import styles from './styles';
import TextInput from '../../containers/TextInput'; import TextInput from '../../containers/TextInput';
import ActivityIndicator from '../../containers/ActivityIndicator'; import ActivityIndicator from '../../containers/ActivityIndicator';
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton'; import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import { isReadOnly, isBlocked } from '../../utils/room'; import { isBlocked } from '../../utils/room';
import { isReadOnly } from '../../utils/isReadOnly';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import { themedHeader } from '../../utils/navigation'; import { themedHeader } from '../../utils/navigation';
@ -69,18 +70,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 +249,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 +262,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();
} }

View File

@ -19,7 +19,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.6.1</string> <string>4.6.4</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>XPC!</string> <string>XPC!</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.6.1</string> <string>4.6.4</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>