[NEW] Permission for uploading files (#3505)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
404c7cff07
commit
a1cee02fb0
|
@ -13,6 +13,7 @@ import { events, logEvent } from '../../utils/log';
|
|||
|
||||
interface IMessageBoxRecordAudioProps {
|
||||
theme: string;
|
||||
permissionToUpload: boolean;
|
||||
recordingCallback: Function;
|
||||
onFinish: Function;
|
||||
}
|
||||
|
@ -192,9 +193,11 @@ export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAu
|
|||
};
|
||||
|
||||
render() {
|
||||
const { theme } = this.props;
|
||||
const { theme, permissionToUpload } = this.props;
|
||||
const { isRecording, isRecorderActive } = this.state;
|
||||
|
||||
if (!permissionToUpload) {
|
||||
return null;
|
||||
}
|
||||
if (!isRecording && !isRecorderActive) {
|
||||
return (
|
||||
<BorderlessButton
|
||||
|
|
|
@ -109,6 +109,8 @@ interface IMessageBoxProps {
|
|||
sharing: boolean;
|
||||
isActionsEnabled: boolean;
|
||||
usedCannedResponse: string;
|
||||
uploadFilePermission: string[];
|
||||
serverVersion: string;
|
||||
}
|
||||
|
||||
interface IMessageBoxState {
|
||||
|
@ -124,6 +126,7 @@ interface IMessageBoxState {
|
|||
};
|
||||
tshow: boolean;
|
||||
mentionLoading: boolean;
|
||||
permissionToUpload: boolean;
|
||||
}
|
||||
|
||||
class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
||||
|
@ -179,41 +182,13 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
showCommandPreview: false,
|
||||
command: {},
|
||||
tshow: false,
|
||||
mentionLoading: false
|
||||
mentionLoading: false,
|
||||
permissionToUpload: true
|
||||
};
|
||||
this.text = '';
|
||||
this.selection = { start: 0, end: 0 };
|
||||
this.focused = false;
|
||||
|
||||
// MessageBox Actions
|
||||
this.options = [
|
||||
{
|
||||
title: I18n.t('Take_a_photo'),
|
||||
icon: 'camera-photo',
|
||||
onPress: this.takePhoto
|
||||
},
|
||||
{
|
||||
title: I18n.t('Take_a_video'),
|
||||
icon: 'camera',
|
||||
onPress: this.takeVideo
|
||||
},
|
||||
{
|
||||
title: I18n.t('Choose_from_library'),
|
||||
icon: 'image',
|
||||
onPress: this.chooseFromLibrary
|
||||
},
|
||||
{
|
||||
title: I18n.t('Choose_file'),
|
||||
icon: 'attach',
|
||||
onPress: this.chooseFile
|
||||
},
|
||||
{
|
||||
title: I18n.t('Create_Discussion'),
|
||||
icon: 'discussions',
|
||||
onPress: this.createDiscussion
|
||||
}
|
||||
];
|
||||
|
||||
const libPickerLabels = {
|
||||
cropperChooseText: I18n.t('Choose'),
|
||||
cropperCancelText: I18n.t('Cancel'),
|
||||
|
@ -277,6 +252,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
this.onChangeText(usedCannedResponse);
|
||||
}
|
||||
|
||||
this.setOptions();
|
||||
|
||||
this.unsubscribeFocus = navigation.addListener('focus', () => {
|
||||
// didFocus
|
||||
// We should wait pushed views be dismissed
|
||||
|
@ -321,10 +298,20 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: any, nextState: any) {
|
||||
const { showEmojiKeyboard, showSend, recording, mentions, commandPreview, tshow, mentionLoading, trackingType } = this.state;
|
||||
shouldComponentUpdate(nextProps: IMessageBoxProps, nextState: IMessageBoxState) {
|
||||
const {
|
||||
showEmojiKeyboard,
|
||||
showSend,
|
||||
recording,
|
||||
mentions,
|
||||
commandPreview,
|
||||
tshow,
|
||||
mentionLoading,
|
||||
trackingType,
|
||||
permissionToUpload
|
||||
} = this.state;
|
||||
|
||||
const { roomType, replying, editing, isFocused, message, theme, usedCannedResponse } = this.props;
|
||||
const { roomType, replying, editing, isFocused, message, theme, usedCannedResponse, uploadFilePermission } = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
|
@ -358,6 +345,9 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
if (nextState.tshow !== tshow) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.permissionToUpload !== permissionToUpload) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextState.mentions, mentions)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -367,12 +357,22 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
if (!dequal(nextProps.message?.id, message?.id)) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.uploadFilePermission, uploadFilePermission)) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.usedCannedResponse !== usedCannedResponse) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: IMessageBoxProps) {
|
||||
const { uploadFilePermission } = this.props;
|
||||
if (!dequal(prevProps.uploadFilePermission, uploadFilePermission)) {
|
||||
this.setOptions();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.countReset(`${this.constructor.name}.render calls`);
|
||||
if (this.onChangeText && this.onChangeText.stop) {
|
||||
|
@ -404,6 +404,19 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
}
|
||||
}
|
||||
|
||||
setOptions = async () => {
|
||||
const { uploadFilePermission, rid } = this.props;
|
||||
|
||||
// Servers older than 4.2
|
||||
if (!uploadFilePermission) {
|
||||
this.setState({ permissionToUpload: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const permissionToUpload = await RocketChat.hasPermission([uploadFilePermission], rid);
|
||||
this.setState({ permissionToUpload: permissionToUpload[0] });
|
||||
};
|
||||
|
||||
onChangeText: any = (text: string): void => {
|
||||
const isTextEmpty = text.length === 0;
|
||||
this.setShowSend(!isTextEmpty);
|
||||
|
@ -666,8 +679,9 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
};
|
||||
|
||||
canUploadFile = (file: any) => {
|
||||
const { permissionToUpload } = this.state;
|
||||
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize } = this.props;
|
||||
const result = canUploadFile(file, FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize);
|
||||
const result = canUploadFile(file, FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize, permissionToUpload);
|
||||
if (result.success) {
|
||||
return true;
|
||||
}
|
||||
|
@ -766,8 +780,41 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
|
||||
showMessageBoxActions = () => {
|
||||
logEvent(events.ROOM_SHOW_BOX_ACTIONS);
|
||||
const { permissionToUpload } = this.state;
|
||||
const { showActionSheet } = this.props;
|
||||
showActionSheet({ options: this.options });
|
||||
|
||||
const options = [];
|
||||
if (permissionToUpload) {
|
||||
options.push(
|
||||
{
|
||||
title: I18n.t('Take_a_photo'),
|
||||
icon: 'camera-photo',
|
||||
onPress: this.takePhoto
|
||||
},
|
||||
{
|
||||
title: I18n.t('Take_a_video'),
|
||||
icon: 'camera',
|
||||
onPress: this.takeVideo
|
||||
},
|
||||
{
|
||||
title: I18n.t('Choose_from_library'),
|
||||
icon: 'image',
|
||||
onPress: this.chooseFromLibrary
|
||||
},
|
||||
{
|
||||
title: I18n.t('Choose_file'),
|
||||
icon: 'attach',
|
||||
onPress: this.chooseFile
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
options.push({
|
||||
title: I18n.t('Create_Discussion'),
|
||||
icon: 'discussions',
|
||||
onPress: this.createDiscussion
|
||||
});
|
||||
showActionSheet({ options });
|
||||
};
|
||||
|
||||
editCancel = () => {
|
||||
|
@ -968,8 +1015,17 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
};
|
||||
|
||||
renderContent = () => {
|
||||
const { recording, showEmojiKeyboard, showSend, mentions, trackingType, commandPreview, showCommandPreview, mentionLoading } =
|
||||
this.state;
|
||||
const {
|
||||
recording,
|
||||
showEmojiKeyboard,
|
||||
showSend,
|
||||
mentions,
|
||||
trackingType,
|
||||
commandPreview,
|
||||
showCommandPreview,
|
||||
mentionLoading,
|
||||
permissionToUpload
|
||||
} = this.state;
|
||||
const {
|
||||
editing,
|
||||
message,
|
||||
|
@ -995,7 +1051,12 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
|
||||
const recordAudio =
|
||||
showSend || !Message_AudioRecorderEnabled ? null : (
|
||||
<RecordAudio theme={theme} recordingCallback={this.recordingCallback} onFinish={this.finishAudioMessage} />
|
||||
<RecordAudio
|
||||
theme={theme}
|
||||
recordingCallback={this.recordingCallback}
|
||||
onFinish={this.finishAudioMessage}
|
||||
permissionToUpload={permissionToUpload}
|
||||
/>
|
||||
);
|
||||
|
||||
const commandsPreviewAndMentions = !recording ? (
|
||||
|
@ -1117,7 +1178,8 @@ const mapStateToProps = (state: any) => ({
|
|||
user: getUserSelector(state),
|
||||
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
|
||||
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize,
|
||||
Message_AudioRecorderEnabled: state.settings.Message_AudioRecorderEnabled
|
||||
Message_AudioRecorderEnabled: state.settings.Message_AudioRecorderEnabled,
|
||||
uploadFilePermission: state.permissions['mobile-upload-file']
|
||||
});
|
||||
|
||||
const dispatchToProps = {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"error-save-video": "Error while saving video",
|
||||
"error-field-unavailable": "{{field}} is already in use :(",
|
||||
"error-file-too-large": "File is too large",
|
||||
"error-not-permission-to-upload-file": "You don't have permission to upload files",
|
||||
"error-importer-not-defined": "The importer was not defined correctly, it is missing the Import class.",
|
||||
"error-input-is-not-a-valid-field": "{{input}} is not a valid {{field}}",
|
||||
"error-invalid-actionlink": "Invalid action link",
|
||||
|
|
|
@ -55,7 +55,8 @@ const PERMISSIONS = [
|
|||
'convert-team',
|
||||
'edit-omnichannel-contact',
|
||||
'edit-livechat-room-customfields',
|
||||
'view-canned-responses'
|
||||
'view-canned-responses',
|
||||
'mobile-upload-file'
|
||||
];
|
||||
|
||||
export async function setPermissions() {
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
export const canUploadFile = (file, allowList, maxFileSize) => {
|
||||
export const canUploadFile = (file, allowList, maxFileSize, permissionToUploadFile) => {
|
||||
if (!(file && file.path)) {
|
||||
return { success: true };
|
||||
}
|
||||
if (maxFileSize > -1 && file.size > maxFileSize) {
|
||||
return { success: false, error: 'error-file-too-large' };
|
||||
}
|
||||
if (!permissionToUploadFile) {
|
||||
return { success: false, error: 'error-not-permission-to-upload-file' };
|
||||
}
|
||||
// if white list is empty, all media types are enabled
|
||||
if (!allowList || allowList === '*') {
|
||||
return { success: true };
|
||||
|
|
|
@ -4,6 +4,7 @@ import { RouteProp } from '@react-navigation/native';
|
|||
import { NativeModules, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import { InsideStackParamList } from '../../stacks/types';
|
||||
import { themes } from '../../constants/colors';
|
||||
|
@ -141,6 +142,17 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
}
|
||||
};
|
||||
|
||||
getPermissionMobileUpload = async () => {
|
||||
const { room } = this.state;
|
||||
const db = database.active;
|
||||
const permissionsCollection = db.get('permissions');
|
||||
const uploadFilePermissionFetch = await permissionsCollection.query(Q.where('id', Q.like('mobile-upload-file'))).fetch();
|
||||
const uploadFilePermission = uploadFilePermissionFetch[0]?.roles;
|
||||
const permissionToUpload = await RocketChat.hasPermission([uploadFilePermission], room.rid);
|
||||
// uploadFilePermission as undefined is considered that there isn't this permission, so all can upload file.
|
||||
return !uploadFilePermission || permissionToUpload[0];
|
||||
};
|
||||
|
||||
getReadOnly = async () => {
|
||||
const { room } = this.state;
|
||||
const { user } = this.props;
|
||||
|
@ -150,10 +162,12 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
|
||||
getAttachments = async () => {
|
||||
const { mediaAllowList, maxFileSize } = this.state;
|
||||
const permissionToUploadFile = await this.getPermissionMobileUpload();
|
||||
|
||||
const items = await Promise.all(
|
||||
this.files.map(async item => {
|
||||
// Check server settings
|
||||
const { success: canUpload, error } = canUploadFile(item, mediaAllowList, maxFileSize);
|
||||
const { success: canUpload, error } = canUploadFile(item, mediaAllowList, maxFileSize, permissionToUploadFile);
|
||||
item.canUpload = canUpload;
|
||||
item.error = error;
|
||||
|
||||
|
|
Loading…
Reference in New Issue