From e5930cc0fedddf007ad2a0fb567916fefc4d4e02 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 7 Feb 2019 14:58:20 -0500 Subject: [PATCH] [FIX] Load avatar on servers that prevent unauthenticated avatar access (#604) App would show an empty space on servers that require authentication on avatar access --- app/containers/Avatar.js | 17 ++++++++++++++--- app/containers/MessageBox/index.js | 23 ++++++++++++++++------- app/containers/message/Message.js | 3 ++- app/presentation/RoomItem.js | 20 ++++++++++++++------ app/presentation/UserItem.js | 8 ++++++-- app/views/CreateChannelView.js | 15 ++++++++++++--- app/views/NewMessageView.js | 15 ++++++++++++--- app/views/ProfileView/index.js | 10 ++++++---- app/views/RoomActionsView/index.js | 19 ++++++++++++------- app/views/RoomInfoView/index.js | 19 +++++++++++++------ app/views/RoomMembersView/index.js | 15 ++++++++++++--- app/views/SelectedUsersView.js | 18 ++++++++++++++---- app/views/SidebarView.js | 4 +++- 13 files changed, 136 insertions(+), 50 deletions(-) diff --git a/app/containers/Avatar.js b/app/containers/Avatar.js index ab858e456..ba55c37fe 100644 --- a/app/containers/Avatar.js +++ b/app/containers/Avatar.js @@ -12,7 +12,11 @@ export default class Avatar extends PureComponent { size: PropTypes.number, borderRadius: PropTypes.number, type: PropTypes.string, - children: PropTypes.object + children: PropTypes.object, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }) } static defaultProps = { @@ -24,7 +28,7 @@ export default class Avatar extends PureComponent { render() { const { - text, size, baseUrl, borderRadius, style, avatar, type, children + text, size, baseUrl, borderRadius, style, avatar, type, children, user } = this.props; const avatarStyle = { @@ -38,9 +42,16 @@ export default class Avatar extends PureComponent { } const room = type === 'd' ? text : `@${ text }`; + // Avoid requesting several sizes by having only two sizes on cache const uriSize = size === 100 ? 100 : 50; - const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }`; + + let avatarAuthURLFragment = ''; + if (user && user.id && user.token) { + avatarAuthURLFragment = `&rc_token=${ user.token }&rc_uid=${ user.id }`; + } + + const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }${ avatarAuthURLFragment }`; const image = ( ({ editCancel: () => dispatch(editCancelAction()), editRequest: message => dispatch(editRequestAction(message)), @@ -68,7 +72,11 @@ export default class MessageBox extends Component { replyMessage: PropTypes.object, replying: PropTypes.bool, editing: PropTypes.bool, - username: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.string, + username: PropTypes.string, + token: PropTypes.string + }), roomType: PropTypes.string, editCancel: PropTypes.func.isRequired, editRequest: PropTypes.func.isRequired, @@ -529,13 +537,13 @@ export default class MessageBox extends Component { editRequest({ _id, msg: message, rid }); } else if (replying) { const { - username, replyMessage, roomType, closeReply + user, replyMessage, roomType, closeReply } = this.props; const permalink = await this.getPermalink(replyMessage); let msg = `[ ](${ permalink }) `; // if original message wasn't sent by current user and neither from a direct room - if (username !== replyMessage.u.username && roomType !== 'd' && replyMessage.mention) { + if (user.username !== replyMessage.u.username && roomType !== 'd' && replyMessage.mention) { msg += `@${ replyMessage.u.username } `; } @@ -617,7 +625,7 @@ export default class MessageBox extends Component { renderMentionItem = (item) => { const { trackingType } = this.state; - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; if (item.username === 'all' || item.username === 'here') { return this.renderFixedMentionItem(item); @@ -641,6 +649,7 @@ export default class MessageBox extends Component { size={30} type={item.username ? 'd' : 'c'} baseUrl={baseUrl} + user={user} />, { item.username || item.name } ] @@ -669,12 +678,12 @@ export default class MessageBox extends Component { renderReplyPreview = () => { const { - replyMessage, replying, closeReply, username + replyMessage, replying, closeReply, user } = this.props; if (!replying) { return null; } - return ; + return ; }; renderFilesActions = () => { diff --git a/app/containers/message/Message.js b/app/containers/message/Message.js index 6657ae770..aead0e65d 100644 --- a/app/containers/message/Message.js +++ b/app/containers/message/Message.js @@ -174,7 +174,7 @@ export default class Message extends PureComponent { renderAvatar = () => { const { - header, avatar, author, baseUrl + header, avatar, author, baseUrl, user } = this.props; if (header) { return ( @@ -185,6 +185,7 @@ export default class Message extends PureComponent { borderRadius={4} avatar={avatar} baseUrl={baseUrl} + user={user} /> ); } diff --git a/app/presentation/RoomItem.js b/app/presentation/RoomItem.js index 46f321304..2fb4cc082 100644 --- a/app/presentation/RoomItem.js +++ b/app/presentation/RoomItem.js @@ -125,7 +125,11 @@ const renderNumber = (unread, userMentions) => { const attrs = ['name', 'unread', 'userMentions', 'alert', 'showLastMessage', 'type']; @connect(state => ({ - username: state.login.user && state.login.user.username, + user: { + id: state.login.user && state.login.user.id, + username: state.login.user && state.login.user.username, + token: state.login.user && state.login.user.token + }, StoreLastMessage: state.settings.Store_Last_Message, baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' })) @@ -144,7 +148,11 @@ export default class RoomItem extends React.Component { userMentions: PropTypes.number, id: PropTypes.string, onPress: PropTypes.func, - username: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.string, + username: PropTypes.string, + token: PropTypes.string + }), avatarSize: PropTypes.number, testID: PropTypes.string, height: PropTypes.number @@ -172,14 +180,14 @@ export default class RoomItem extends React.Component { get avatar() { const { - type, name, avatarSize, baseUrl + type, name, avatarSize, baseUrl, user } = this.props; - return ; + return ; } get lastMessage() { const { - lastMessage, type, showLastMessage, StoreLastMessage, username + lastMessage, type, showLastMessage, StoreLastMessage, user } = this.props; if (!StoreLastMessage || !showLastMessage) { @@ -190,7 +198,7 @@ export default class RoomItem extends React.Component { } let prefix = ''; - const me = lastMessage.u.username === username; + const me = lastMessage.u.username === user.username; if (!lastMessage.msg && Object.keys(lastMessage.attachments).length > 0) { if (me) { diff --git a/app/presentation/UserItem.js b/app/presentation/UserItem.js index 52b131409..3605255eb 100644 --- a/app/presentation/UserItem.js +++ b/app/presentation/UserItem.js @@ -45,11 +45,11 @@ const styles = StyleSheet.create({ }); const UserItem = ({ - name, username, onPress, testID, onLongPress, style, icon, baseUrl + name, username, onPress, testID, onLongPress, style, icon, baseUrl, user }) => ( - + {name} @{username} @@ -62,6 +62,10 @@ const UserItem = ({ UserItem.propTypes = { name: PropTypes.string.isRequired, username: PropTypes.string.isRequired, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }), baseUrl: PropTypes.string.isRequired, onPress: PropTypes.func.isRequired, testID: PropTypes.string.isRequired, diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 4ee6a576a..07df8ca66 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -80,7 +80,11 @@ const styles = StyleSheet.create({ failure: state.createChannel.failure, isFetching: state.createChannel.isFetching, result: state.createChannel.result, - users: state.selectedUsers.users + users: state.selectedUsers.users, + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + } }), dispatch => ({ create: data => dispatch(createChannelRequestAction(data)), removeUser: user => dispatch(removeUserAction(user)) @@ -106,7 +110,11 @@ export default class CreateChannelView extends LoggedView { failure: PropTypes.bool, isFetching: PropTypes.bool, result: PropTypes.object, - users: PropTypes.array.isRequired + users: PropTypes.array.isRequired, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }) }; constructor(props) { @@ -305,7 +313,7 @@ export default class CreateChannelView extends LoggedView { renderFormSeparator = () => renderItem = ({ item }) => { - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( this.removeUser(item)} testID={`create-channel-view-item-${ item.name }`} baseUrl={baseUrl} + user={user} /> ); } diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index c52438d2a..1ea25f46a 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -49,7 +49,11 @@ const styles = StyleSheet.create({ }); @connect(state => ({ - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' + baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + } })) /** @extends React.Component */ export default class NewMessageView extends LoggedView { @@ -68,7 +72,11 @@ export default class NewMessageView extends LoggedView { static propTypes = { componentId: PropTypes.string, baseUrl: PropTypes.string, - onPressItem: PropTypes.func.isRequired + onPressItem: PropTypes.func.isRequired, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }) }; constructor(props) { @@ -162,7 +170,7 @@ export default class NewMessageView extends LoggedView { renderItem = ({ item, index }) => { const { search } = this.state; - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; let style = {}; if (index === 0) { @@ -182,6 +190,7 @@ export default class NewMessageView extends LoggedView { baseUrl={baseUrl} testID={`new-message-view-item-${ item.name }`} style={style} + user={user} /> ); } diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index 31cb91228..27f00ea84 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -36,7 +36,8 @@ import Icons from '../../lib/Icons'; name: state.login.user && state.login.user.name, username: state.login.user && state.login.user.username, customFields: state.login.user && state.login.user.customFields, - emails: state.login.user && state.login.user.emails + emails: state.login.user && state.login.user.emails, + token: state.login.user && state.login.user.token }, Accounts_CustomFields: state.settings.Accounts_CustomFields, baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' @@ -326,7 +327,7 @@ export default class ProfileView extends LoggedView { return ( {this.renderAvatarButton({ - child: , + child: , onPress: () => this.resetAvatar(), key: 'profile-view-reset-avatar' })} @@ -345,7 +346,7 @@ export default class ProfileView extends LoggedView { const { url, blob, contentType } = avatarSuggestions[service]; return this.renderAvatarButton({ key: `profile-view-avatar-${ service }`, - child: , + child: , onPress: () => this.setAvatar({ url, data: blob, service, contentType }) @@ -419,7 +420,7 @@ export default class ProfileView extends LoggedView { const { name, username, email, newPassword, avatarUrl, customFields, avatar, saving, showPasswordAlert } = this.state; - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( ; @connect(state => ({ - userId: state.login.user && state.login.user.id, - username: state.login.user && state.login.user.username, + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + }, baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', room: state.room }), dispatch => ({ @@ -50,8 +52,10 @@ export default class RoomActionsView extends LoggedView { baseUrl: PropTypes.string, rid: PropTypes.string, componentId: PropTypes.string, - userId: PropTypes.string, - username: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }), room: PropTypes.object, leaveRoom: PropTypes.func } @@ -333,10 +337,10 @@ export default class RoomActionsView extends LoggedView { updateRoomMember = async() => { const { room } = this.state; const { rid } = room; - const { userId } = this.props; + const { user } = this.props; try { - const member = await RocketChat.getRoomMember(rid, userId); + const member = await RocketChat.getRoomMember(rid, user.id); this.setState({ member: member || {} }); } catch (e) { log('RoomActions updateRoomMember', e); @@ -391,7 +395,7 @@ export default class RoomActionsView extends LoggedView { renderRoomInfo = ({ item }) => { const { room, member } = this.state; const { name, t, topic } = room; - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( this.renderTouchableItem([ @@ -402,6 +406,7 @@ export default class RoomActionsView extends LoggedView { style={styles.avatar} type={t} baseUrl={baseUrl} + user={user} > {t === 'd' ? : null } , diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js index 3ce9aabe6..a29a1e9ab 100644 --- a/app/views/RoomInfoView/index.js +++ b/app/views/RoomInfoView/index.js @@ -34,7 +34,10 @@ const getRoomTitle = room => (room.t === 'd' @connect(state => ({ baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', - userId: state.login.user && state.login.user.id, + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + }, activeUsers: state.activeUsers, // TODO: remove it Message_TimeFormat: state.settings.Message_TimeFormat, allRoles: state.roles, @@ -55,7 +58,10 @@ export default class RoomInfoView extends LoggedView { static propTypes = { componentId: PropTypes.string, rid: PropTypes.string, - userId: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }), baseUrl: PropTypes.string, activeUsers: PropTypes.object, Message_TimeFormat: PropTypes.string, @@ -105,8 +111,8 @@ export default class RoomInfoView extends LoggedView { if (room) { if (room.t === 'd') { try { - const { userId, activeUsers } = this.props; - const roomUser = await RocketChat.getRoomMember(room.rid, userId); + const { user, activeUsers } = this.props; + const roomUser = await RocketChat.getRoomMember(room.rid, user.id); this.setState({ roomUser: roomUser || {} }); const username = room.name; @@ -120,7 +126,7 @@ export default class RoomInfoView extends LoggedView { // get all users roles // needs to be changed by a better method const allUsersRoles = await RocketChat.getUserRoles(); - const userRoles = allUsersRoles.find(user => user.username === username); + const userRoles = allUsersRoles.find(u => u.username === username); if (userRoles) { this.setState({ roles: userRoles.roles || [] }); } @@ -246,7 +252,7 @@ export default class RoomInfoView extends LoggedView { } renderAvatar = (room, roomUser) => { - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( {room.t === 'd' ? : null} diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 69f30ee3b..92e78d082 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -23,7 +23,11 @@ import SearchBox from '../../containers/SearchBox'; @connect(state => ({ baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', - room: state.room + room: state.room, + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + } })) /** @extends React.Component */ export default class RoomMembersView extends LoggedView { @@ -48,7 +52,11 @@ export default class RoomMembersView extends LoggedView { rid: PropTypes.string, members: PropTypes.array, baseUrl: PropTypes.string, - room: PropTypes.object + room: PropTypes.object, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }) } constructor(props) { @@ -243,7 +251,7 @@ export default class RoomMembersView extends LoggedView { renderSeparator = () => ; renderItem = ({ item }) => { - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( this.onLongPressUser(item)} baseUrl={baseUrl} testID={`room-members-view-item-${ item.username }`} + user={user} /> ); } diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.js index da7d40c3c..aea1d114c 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.js @@ -39,7 +39,11 @@ const styles = StyleSheet.create({ @connect(state => ({ baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', users: state.selectedUsers.users, - loading: state.selectedUsers.loading + loading: state.selectedUsers.loading, + user: { + id: state.login.user && state.login.user.id, + token: state.login.user && state.login.user.token + } }), dispatch => ({ addUser: user => dispatch(addUserAction(user)), removeUser: user => dispatch(removeUserAction(user)), @@ -58,7 +62,11 @@ export default class SelectedUsersView extends LoggedView { reset: PropTypes.func.isRequired, users: PropTypes.array, loading: PropTypes.bool, - setLoadingInvite: PropTypes.func + setLoadingInvite: PropTypes.func, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }) }; constructor(props) { @@ -209,7 +217,7 @@ export default class SelectedUsersView extends LoggedView { } renderSelectedItem = ({ item }) => { - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; return ( ); } @@ -226,7 +235,7 @@ export default class SelectedUsersView extends LoggedView { renderItem = ({ item, index }) => { const { search } = this.state; - const { baseUrl } = this.props; + const { baseUrl, user } = this.props; const name = item.search ? item.name : item.fname; const username = item.search ? item.username : item.name; @@ -249,6 +258,7 @@ export default class SelectedUsersView extends LoggedView { icon={this.isChecked(username) ? 'check' : null} baseUrl={baseUrl} style={style} + user={user} /> ); } diff --git a/app/views/SidebarView.js b/app/views/SidebarView.js index da7085b08..0408c3e76 100644 --- a/app/views/SidebarView.js +++ b/app/views/SidebarView.js @@ -90,7 +90,8 @@ const keyExtractor = item => item.id; id: state.login.user && state.login.user.id, language: state.login.user && state.login.user.language, status: state.login.user && state.login.user.status, - username: state.login.user && state.login.user.username + username: state.login.user && state.login.user.username, + token: state.login.user && state.login.user.token }, baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' }), dispatch => ({ @@ -340,6 +341,7 @@ export default class Sidebar extends Component { size={30} style={styles.avatar} baseUrl={baseUrl} + user={user} />