[CHORE] Add permissions to Redux (#2914)
* [FIX] Add permissions to Redux store * add only permissions being used in the app * add clear permissions reducer * call RocketChat.hasPermission from reducer * add server version comparison on getPermissions * refactor hasPermission function * refactor hasPermission function * remove uncomment code * use Q.experimentalSortBy() * add coerce function * Change Rocketchat.hasPermission * Apply on isReadOnly * Apply to RoomInfoEditView * Apply to RoomInfoView and RoomInfoEditView * canAutoTranslate * Unnecessary clear permissions * Revert getUpdatedSince * Naming fix Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
6e32a15cad
commit
e98116587d
|
@ -70,3 +70,5 @@ export const SETTINGS = createRequestTypes('SETTINGS', ['CLEAR', 'ADD']);
|
|||
export const APP_STATE = createRequestTypes('APP_STATE', ['FOREGROUND', 'BACKGROUND']);
|
||||
export const ENTERPRISE_MODULES = createRequestTypes('ENTERPRISE_MODULES', ['CLEAR', 'SET']);
|
||||
export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DECODE_KEY', 'SET', 'SET_BANNER']);
|
||||
|
||||
export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET']);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function setPermissions(permissions) {
|
||||
return {
|
||||
type: types.PERMISSIONS.SET,
|
||||
permissions
|
||||
};
|
||||
}
|
|
@ -34,20 +34,24 @@ const MessageActions = React.memo(forwardRef(({
|
|||
Message_AllowPinning,
|
||||
Message_AllowStarring,
|
||||
Message_Read_Receipt_Store_Users,
|
||||
isMasterDetail
|
||||
isMasterDetail,
|
||||
editMessagePermission,
|
||||
deleteMessagePermission,
|
||||
forceDeleteMessagePermission,
|
||||
pinMessagePermission
|
||||
}, ref) => {
|
||||
let permissions = {};
|
||||
const { showActionSheet, hideActionSheet } = useActionSheet();
|
||||
|
||||
const getPermissions = async() => {
|
||||
try {
|
||||
const permission = ['edit-message', 'delete-message', 'force-delete-message', 'pin-message'];
|
||||
const permission = [editMessagePermission, deleteMessagePermission, forceDeleteMessagePermission, pinMessagePermission];
|
||||
const result = await RocketChat.hasPermission(permission, room.rid);
|
||||
permissions = {
|
||||
hasEditPermission: result[permission[0]],
|
||||
hasDeletePermission: result[permission[1]],
|
||||
hasForceDeletePermission: result[permission[2]],
|
||||
hasPinPermission: result[permission[3]]
|
||||
hasEditPermission: result[0],
|
||||
hasDeletePermission: result[1],
|
||||
hasForceDeletePermission: result[2],
|
||||
hasPinPermission: result[3]
|
||||
};
|
||||
} catch {
|
||||
// Do nothing
|
||||
|
@ -440,7 +444,11 @@ MessageActions.propTypes = {
|
|||
Message_AllowPinning: PropTypes.bool,
|
||||
Message_AllowStarring: PropTypes.bool,
|
||||
Message_Read_Receipt_Store_Users: PropTypes.bool,
|
||||
server: PropTypes.string
|
||||
server: PropTypes.string,
|
||||
editMessagePermission: PropTypes.array,
|
||||
deleteMessagePermission: PropTypes.array,
|
||||
forceDeleteMessagePermission: PropTypes.array,
|
||||
pinMessagePermission: PropTypes.array
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
|
@ -452,7 +460,11 @@ const mapStateToProps = state => ({
|
|||
Message_AllowPinning: state.settings.Message_AllowPinning,
|
||||
Message_AllowStarring: state.settings.Message_AllowStarring,
|
||||
Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users,
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
editMessagePermission: state.permissions['edit-message'],
|
||||
deleteMessagePermission: state.permissions['delete-message'],
|
||||
forceDeleteMessagePermission: state.permissions['force-delete-message'],
|
||||
pinMessagePermission: state.permissions['pin-message']
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null, null, { forwardRef: true })(MessageActions);
|
||||
|
|
|
@ -1,11 +1,55 @@
|
|||
import lt from 'semver/functions/lt';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import coerce from 'semver/functions/coerce';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import reduxStore from '../createStore';
|
||||
import protectedFunction from './helpers/protectedFunction';
|
||||
import { setPermissions as setPermissionsAction } from '../../actions/permissions';
|
||||
|
||||
const PERMISSIONS = [
|
||||
'add-user-to-any-c-room',
|
||||
'add-user-to-any-p-room',
|
||||
'add-user-to-joined-room',
|
||||
'archive-room',
|
||||
'auto-translate',
|
||||
'create-invite-links',
|
||||
'delete-c',
|
||||
'delete-message',
|
||||
'delete-p',
|
||||
'edit-message',
|
||||
'edit-room',
|
||||
'force-delete-message',
|
||||
'mute-user',
|
||||
'pin-message',
|
||||
'post-readonly',
|
||||
'remove-user',
|
||||
'set-leader',
|
||||
'set-moderator',
|
||||
'set-owner',
|
||||
'set-react-when-readonly',
|
||||
'set-readonly',
|
||||
'toggle-room-e2e-encryption',
|
||||
'transfer-livechat-guest',
|
||||
'unarchive-room',
|
||||
'view-broadcast-member-list',
|
||||
'view-privileged-setting',
|
||||
'view-room-administration',
|
||||
'view-statistics',
|
||||
'view-user-administration'
|
||||
];
|
||||
|
||||
export async function setPermissions() {
|
||||
const db = database.active;
|
||||
const permissionsCollection = db.collections.get('permissions');
|
||||
const allPermissions = await permissionsCollection.query(Q.where('id', Q.oneOf(PERMISSIONS))).fetch();
|
||||
const parsed = allPermissions.reduce((acc, item) => ({ ...acc, [item.id]: item.roles }), {});
|
||||
|
||||
reduxStore.dispatch(setPermissionsAction(parsed));
|
||||
}
|
||||
|
||||
const getUpdatedSince = (allRecords) => {
|
||||
try {
|
||||
|
@ -64,12 +108,13 @@ const updatePermissions = async({ update = [], remove = [], allRecords }) => {
|
|||
await db.action(async() => {
|
||||
await db.batch(...batch);
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export default function() {
|
||||
export function getPermissions() {
|
||||
return new Promise(async(resolve) => {
|
||||
try {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
|
@ -78,17 +123,20 @@ export default function() {
|
|||
const allRecords = await permissionsCollection.query().fetch();
|
||||
|
||||
// if server version is lower than 0.73.0, fetches from old api
|
||||
if (serverVersion && lt(serverVersion, '0.73.0')) {
|
||||
if (serverVersion && lt(coerce(serverVersion), '0.73.0')) {
|
||||
// RC 0.66.0
|
||||
const result = await this.sdk.get('permissions.list');
|
||||
if (!result.success) {
|
||||
return resolve();
|
||||
}
|
||||
await updatePermissions({ update: result.permissions, allRecords });
|
||||
const changePermissions = await updatePermissions({ update: result.permissions, allRecords });
|
||||
if (changePermissions) {
|
||||
setPermissions();
|
||||
}
|
||||
return resolve();
|
||||
} else {
|
||||
const params = {};
|
||||
const updatedSince = await getUpdatedSince(allRecords);
|
||||
const updatedSince = getUpdatedSince(allRecords);
|
||||
if (updatedSince) {
|
||||
params.updatedSince = updatedSince;
|
||||
}
|
||||
|
@ -99,7 +147,10 @@ export default function() {
|
|||
return resolve();
|
||||
}
|
||||
|
||||
await updatePermissions({ update: result.update, remove: result.delete, allRecords });
|
||||
const changePermissions = await updatePermissions({ update: result.update, remove: result.delete, allRecords });
|
||||
if (changePermissions) {
|
||||
setPermissions();
|
||||
}
|
||||
return resolve();
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -32,7 +32,7 @@ import readMessages from './methods/readMessages';
|
|||
import getSettings, { getLoginSettings, setSettings } from './methods/getSettings';
|
||||
|
||||
import getRooms from './methods/getRooms';
|
||||
import getPermissions from './methods/getPermissions';
|
||||
import { setPermissions, getPermissions } from './methods/getPermissions';
|
||||
import { getCustomEmojis, setCustomEmojis } from './methods/getCustomEmojis';
|
||||
import {
|
||||
getEnterpriseModules, setEnterpriseModules, hasLicense, isOmnichannelModuleAvailable
|
||||
|
@ -70,7 +70,6 @@ const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY';
|
|||
export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
|
||||
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
||||
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
||||
const returnAnArray = obj => obj || [];
|
||||
const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
||||
|
||||
const STATUSES = ['offline', 'online', 'away', 'busy'];
|
||||
|
@ -740,6 +739,7 @@ const RocketChat = {
|
|||
getLoginSettings,
|
||||
setSettings,
|
||||
getPermissions,
|
||||
setPermissions,
|
||||
getCustomEmojis,
|
||||
setCustomEmojis,
|
||||
getEnterpriseModules,
|
||||
|
@ -1172,10 +1172,13 @@ const RocketChat = {
|
|||
// RC 0.65.0
|
||||
return this.sdk.get(`${ this.roomTypeToApiType(type) }.roles`, { roomId });
|
||||
},
|
||||
/**
|
||||
* Permissions: array of permissions' roles from redux. Example: [['owner', 'admin'], ['leader']]
|
||||
* Returns an array of boolean for each permission from permissions arg
|
||||
*/
|
||||
async hasPermission(permissions, rid) {
|
||||
const db = database.active;
|
||||
const subsCollection = db.collections.get('subscriptions');
|
||||
const permissionsCollection = db.collections.get('permissions');
|
||||
let roomRoles = [];
|
||||
try {
|
||||
// get the room from database
|
||||
|
@ -1184,31 +1187,16 @@ const RocketChat = {
|
|||
roomRoles = room.roles || [];
|
||||
} catch (error) {
|
||||
console.log('hasPermission -> Room not found');
|
||||
return permissions.reduce((result, permission) => {
|
||||
result[permission] = false;
|
||||
return result;
|
||||
}, {});
|
||||
return permissions.map(() => false);
|
||||
}
|
||||
// get permissions from database
|
||||
|
||||
try {
|
||||
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
|
||||
const userRoles = (shareUser?.roles || loginUser?.roles) || [];
|
||||
// merge both roles
|
||||
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
|
||||
|
||||
// return permissions in object format
|
||||
// e.g. { 'edit-room': true, 'set-readonly': false }
|
||||
return permissions.reduce((result, permission) => {
|
||||
result[permission] = false;
|
||||
const permissionFound = permissionsFiltered.find(p => p.id === permission);
|
||||
if (permissionFound) {
|
||||
result[permission] = returnAnArray(permissionFound.roles).some(r => mergedRoles.includes(r));
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
return permissions.map(permission => permission.some(r => mergedRoles.includes(r) ?? false));
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
@ -1438,17 +1426,15 @@ const RocketChat = {
|
|||
query, count, offset, sort
|
||||
});
|
||||
},
|
||||
async canAutoTranslate() {
|
||||
const db = database.active;
|
||||
canAutoTranslate() {
|
||||
try {
|
||||
const AutoTranslate_Enabled = reduxStore.getState().settings && reduxStore.getState().settings.AutoTranslate_Enabled;
|
||||
const { AutoTranslate_Enabled } = reduxStore.getState().settings;
|
||||
if (!AutoTranslate_Enabled) {
|
||||
return false;
|
||||
}
|
||||
const permissionsCollection = db.collections.get('permissions');
|
||||
const autoTranslatePermission = await permissionsCollection.find('auto-translate');
|
||||
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
|
||||
return autoTranslatePermission.roles.some(role => userRoles.includes(role));
|
||||
const autoTranslatePermission = reduxStore.getState().permissions['auto-translate'];
|
||||
const userRoles = (reduxStore.getState().login?.user?.roles) ?? [];
|
||||
return autoTranslatePermission?.some(role => userRoles.includes(role));
|
||||
} catch (e) {
|
||||
log(e);
|
||||
return false;
|
||||
|
|
|
@ -18,6 +18,7 @@ import inviteLinks from './inviteLinks';
|
|||
import createDiscussion from './createDiscussion';
|
||||
import enterpriseModules from './enterpriseModules';
|
||||
import encryption from './encryption';
|
||||
import permissions from './permissions';
|
||||
|
||||
import inquiry from '../ee/omnichannel/reducers/inquiry';
|
||||
|
||||
|
@ -41,5 +42,6 @@ export default combineReducers({
|
|||
createDiscussion,
|
||||
inquiry,
|
||||
enterpriseModules,
|
||||
encryption
|
||||
encryption,
|
||||
permissions
|
||||
});
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { PERMISSIONS } from '../actions/actionsTypes';
|
||||
|
||||
const initialState = {
|
||||
permissions: {}
|
||||
};
|
||||
|
||||
export default function permissions(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case PERMISSIONS.SET:
|
||||
return action.permissions;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -124,6 +124,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
|
|||
// and block the selectServerSuccess raising multiples errors
|
||||
RocketChat.setSettings();
|
||||
RocketChat.setCustomEmojis();
|
||||
RocketChat.setPermissions();
|
||||
RocketChat.setEnterpriseModules();
|
||||
|
||||
let serverInfo;
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import RocketChat from '../lib/rocketchat';
|
||||
import reduxStore from '../lib/createStore';
|
||||
|
||||
const canPost = async({ rid }) => {
|
||||
try {
|
||||
const permission = await RocketChat.hasPermission(['post-readonly'], rid);
|
||||
return permission && permission['post-readonly'];
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
return false;
|
||||
const canPostReadOnly = async({ rid }) => {
|
||||
// TODO: this is not reactive. If this permission changes, the component won't be updated
|
||||
const postReadOnlyPermission = reduxStore.getState().permissions['post-readonly'];
|
||||
const permission = await RocketChat.hasPermission([postReadOnlyPermission], rid);
|
||||
return permission[0];
|
||||
};
|
||||
|
||||
const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
|
||||
|
@ -20,7 +18,7 @@ export const isReadOnly = async(room, user) => {
|
|||
return true;
|
||||
}
|
||||
if (room?.ro) {
|
||||
const allowPost = await canPost(room);
|
||||
const allowPost = await canPostReadOnly(room);
|
||||
if (allowPost) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,15 @@ class RoomActionsView extends React.Component {
|
|||
closeRoom: PropTypes.func,
|
||||
theme: PropTypes.string,
|
||||
fontScale: PropTypes.number,
|
||||
serverVersion: PropTypes.string
|
||||
serverVersion: PropTypes.string,
|
||||
addUserToJoinedRoomPermission: PropTypes.array,
|
||||
addUserToAnyCRoomPermission: PropTypes.array,
|
||||
addUserToAnyPRoomPermission: PropTypes.array,
|
||||
createInviteLinksPermission: PropTypes.array,
|
||||
editRoomPermission: PropTypes.array,
|
||||
toggleRoomE2EEncryptionPermission: PropTypes.array,
|
||||
viewBroadcastMemberListPermission: PropTypes.array,
|
||||
transferLivechatGuestPermission: PropTypes.array
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -118,7 +126,7 @@ class RoomActionsView extends React.Component {
|
|||
this.updateRoomMember();
|
||||
}
|
||||
|
||||
const canAutoTranslate = await RocketChat.canAutoTranslate();
|
||||
const canAutoTranslate = RocketChat.canAutoTranslate();
|
||||
this.setState({ canAutoTranslate });
|
||||
|
||||
this.canAddUser();
|
||||
|
@ -159,60 +167,62 @@ class RoomActionsView extends React.Component {
|
|||
|
||||
canAddUser = async() => {
|
||||
const { room, joined } = this.state;
|
||||
const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props;
|
||||
const { rid, t } = room;
|
||||
let canAdd = false;
|
||||
let canAddUser = false;
|
||||
|
||||
const userInRoom = joined;
|
||||
const permissions = await RocketChat.hasPermission(['add-user-to-joined-room', 'add-user-to-any-c-room', 'add-user-to-any-p-room'], rid);
|
||||
const permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid);
|
||||
|
||||
if (permissions) {
|
||||
if (userInRoom && permissions['add-user-to-joined-room']) {
|
||||
canAdd = true;
|
||||
}
|
||||
if (t === 'c' && permissions['add-user-to-any-c-room']) {
|
||||
canAdd = true;
|
||||
}
|
||||
if (t === 'p' && permissions['add-user-to-any-p-room']) {
|
||||
canAdd = true;
|
||||
}
|
||||
if (userInRoom && permissions[0]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
this.setState({ canAddUser: canAdd });
|
||||
if (t === 'c' && permissions[1]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
if (t === 'p' && permissions[2]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
this.setState({ canAddUser });
|
||||
}
|
||||
|
||||
canInviteUser = async() => {
|
||||
const { room } = this.state;
|
||||
const { createInviteLinksPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await RocketChat.hasPermission(['create-invite-links'], rid);
|
||||
const permissions = await RocketChat.hasPermission([createInviteLinksPermission], rid);
|
||||
|
||||
const canInviteUser = permissions && permissions['create-invite-links'];
|
||||
const canInviteUser = permissions[0];
|
||||
this.setState({ canInviteUser });
|
||||
}
|
||||
|
||||
canEdit = async() => {
|
||||
const { room } = this.state;
|
||||
const { editRoomPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await RocketChat.hasPermission(['edit-room'], rid);
|
||||
const permissions = await RocketChat.hasPermission([editRoomPermission], rid);
|
||||
|
||||
const canEdit = permissions && permissions['edit-room'];
|
||||
const canEdit = permissions[0];
|
||||
this.setState({ canEdit });
|
||||
}
|
||||
|
||||
canToggleEncryption = async() => {
|
||||
const { room } = this.state;
|
||||
const { toggleRoomE2EEncryptionPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await RocketChat.hasPermission(['toggle-room-e2e-encryption'], rid);
|
||||
const permissions = await RocketChat.hasPermission([toggleRoomE2EEncryptionPermission], rid);
|
||||
|
||||
const canToggleEncryption = permissions && permissions['toggle-room-e2e-encryption'];
|
||||
const canToggleEncryption = permissions[0];
|
||||
this.setState({ canToggleEncryption });
|
||||
}
|
||||
|
||||
canViewMembers = async() => {
|
||||
const { room } = this.state;
|
||||
const { viewBroadcastMemberListPermission } = this.props;
|
||||
const { rid, t, broadcast } = room;
|
||||
if (broadcast) {
|
||||
const viewBroadcastMemberListPermission = 'view-broadcast-member-list';
|
||||
const permissions = await RocketChat.hasPermission([viewBroadcastMemberListPermission], rid);
|
||||
if (!permissions[viewBroadcastMemberListPermission]) {
|
||||
if (!permissions[0]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -226,16 +236,10 @@ class RoomActionsView extends React.Component {
|
|||
|
||||
canForwardGuest = async() => {
|
||||
const { room } = this.state;
|
||||
const { transferLivechatGuestPermission } = this.props;
|
||||
const { rid } = room;
|
||||
let result = true;
|
||||
|
||||
const transferLivechatGuest = 'transfer-livechat-guest';
|
||||
const permissions = await RocketChat.hasPermission([transferLivechatGuest], rid);
|
||||
if (!permissions[transferLivechatGuest]) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
this.setState({ canForwardGuest: result });
|
||||
const permissions = await RocketChat.hasPermission([transferLivechatGuestPermission], rid);
|
||||
this.setState({ canForwardGuest: permissions[0] });
|
||||
}
|
||||
|
||||
canReturnQueue = async() => {
|
||||
|
@ -866,7 +870,15 @@ class RoomActionsView extends React.Component {
|
|||
const mapStateToProps = state => ({
|
||||
jitsiEnabled: state.settings.Jitsi_Enabled || false,
|
||||
encryptionEnabled: state.encryption.enabled,
|
||||
serverVersion: state.server.version
|
||||
serverVersion: state.server.version,
|
||||
addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'],
|
||||
addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'],
|
||||
addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'],
|
||||
createInviteLinksPermission: state.permissions['create-invite-links'],
|
||||
editRoomPermission: state.permissions['edit-room'],
|
||||
toggleRoomE2EEncryptionPermission: state.permissions['toggle-room-e2e-encryption'],
|
||||
viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'],
|
||||
transferLivechatGuestPermission: state.permissions['transfer-livechat-guest']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -44,14 +44,6 @@ const PERMISSION_ARCHIVE = 'archive-room';
|
|||
const PERMISSION_UNARCHIVE = 'unarchive-room';
|
||||
const PERMISSION_DELETE_C = 'delete-c';
|
||||
const PERMISSION_DELETE_P = 'delete-p';
|
||||
const PERMISSIONS_ARRAY = [
|
||||
PERMISSION_SET_READONLY,
|
||||
PERMISSION_SET_REACT_WHEN_READONLY,
|
||||
PERMISSION_ARCHIVE,
|
||||
PERMISSION_UNARCHIVE,
|
||||
PERMISSION_DELETE_C,
|
||||
PERMISSION_DELETE_P
|
||||
];
|
||||
|
||||
class RoomInfoEditView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
|
@ -63,7 +55,13 @@ class RoomInfoEditView extends React.Component {
|
|||
deleteRoom: PropTypes.func,
|
||||
serverVersion: PropTypes.string,
|
||||
encryptionEnabled: PropTypes.bool,
|
||||
theme: PropTypes.string
|
||||
theme: PropTypes.string,
|
||||
setReadOnlyPermission: PropTypes.array,
|
||||
setReactWhenReadOnlyPermission: PropTypes.array,
|
||||
archiveRoomPermission: PropTypes.array,
|
||||
unarchiveRoomPermission: PropTypes.array,
|
||||
deleteCPermission: PropTypes.array,
|
||||
deletePPermission: PropTypes.array
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -108,7 +106,15 @@ class RoomInfoEditView extends React.Component {
|
|||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
loadRoom = async() => {
|
||||
const { route } = this.props;
|
||||
const {
|
||||
route,
|
||||
setReadOnlyPermission,
|
||||
setReactWhenReadOnlyPermission,
|
||||
archiveRoomPermission,
|
||||
unarchiveRoomPermission,
|
||||
deleteCPermission,
|
||||
deletePPermission
|
||||
} = this.props;
|
||||
const rid = route.params?.rid;
|
||||
if (!rid) {
|
||||
return;
|
||||
|
@ -123,8 +129,25 @@ class RoomInfoEditView extends React.Component {
|
|||
this.init(this.room);
|
||||
});
|
||||
|
||||
const permissions = await RocketChat.hasPermission(PERMISSIONS_ARRAY, rid);
|
||||
this.setState({ permissions });
|
||||
const result = await RocketChat.hasPermission([
|
||||
setReadOnlyPermission,
|
||||
setReactWhenReadOnlyPermission,
|
||||
archiveRoomPermission,
|
||||
unarchiveRoomPermission,
|
||||
deleteCPermission,
|
||||
deletePPermission
|
||||
], rid);
|
||||
|
||||
this.setState({
|
||||
permissions: {
|
||||
[PERMISSION_SET_READONLY]: result[0],
|
||||
[PERMISSION_SET_REACT_WHEN_READONLY]: result[1],
|
||||
[PERMISSION_ARCHIVE]: result[2],
|
||||
[PERMISSION_UNARCHIVE]: result[3],
|
||||
[PERMISSION_DELETE_C]: result[4],
|
||||
[PERMISSION_DELETE_P]: result[5]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
@ -667,7 +690,13 @@ class RoomInfoEditView extends React.Component {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
serverVersion: state.server.version,
|
||||
encryptionEnabled: state.encryption.enabled
|
||||
encryptionEnabled: state.encryption.enabled,
|
||||
setReadOnlyPermission: state.permissions[PERMISSION_SET_READONLY],
|
||||
setReactWhenReadOnlyPermission: state.permissions[PERMISSION_SET_REACT_WHEN_READONLY],
|
||||
archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE],
|
||||
unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE],
|
||||
deleteCPermission: state.permissions[PERMISSION_DELETE_C],
|
||||
deletePPermission: state.permissions[PERMISSION_DELETE_P]
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -31,7 +31,6 @@ import SafeAreaView from '../../containers/SafeAreaView';
|
|||
import { goRoom } from '../../utils/goRoom';
|
||||
import Navigation from '../../lib/Navigation';
|
||||
|
||||
const PERMISSION_EDIT_ROOM = 'edit-room';
|
||||
const getRoomTitle = (room, type, name, username, statusText, theme) => (type === 'd'
|
||||
? (
|
||||
<>
|
||||
|
@ -55,7 +54,8 @@ class RoomInfoView extends React.Component {
|
|||
rooms: PropTypes.array,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
jitsiEnabled: PropTypes.bool
|
||||
jitsiEnabled: PropTypes.bool,
|
||||
editRoomPermission: PropTypes.array
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -193,7 +193,7 @@ class RoomInfoView extends React.Component {
|
|||
|
||||
loadRoom = async() => {
|
||||
const { room: roomState } = this.state;
|
||||
const { route } = this.props;
|
||||
const { route, editRoomPermission } = this.props;
|
||||
let room = route.params?.room;
|
||||
if (room && room.observe) {
|
||||
this.roomObservable = room.observe();
|
||||
|
@ -213,8 +213,8 @@ class RoomInfoView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const permissions = await RocketChat.hasPermission([PERMISSION_EDIT_ROOM], room.rid);
|
||||
if (permissions[PERMISSION_EDIT_ROOM] && !room.prid) {
|
||||
const permissions = await RocketChat.hasPermission([editRoomPermission], room.rid);
|
||||
if (permissions[0] && !room.prid) {
|
||||
this.setState({ showEdit: true }, () => this.setHeader());
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +369,8 @@ class RoomInfoView extends React.Component {
|
|||
const mapStateToProps = state => ({
|
||||
rooms: state.room.rooms,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
jitsiEnabled: state.settings.Jitsi_Enabled || false
|
||||
jitsiEnabled: state.settings.Jitsi_Enabled || false,
|
||||
editRoomPermission: state.permissions['edit-room']
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(RoomInfoView));
|
||||
|
|
|
@ -28,6 +28,12 @@ import { goRoom } from '../../utils/goRoom';
|
|||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
const PERMISSION_MUTE_USER = 'mute-user';
|
||||
const PERMISSION_SET_LEADER = 'set-leader';
|
||||
const PERMISSION_SET_OWNER = 'set-owner';
|
||||
const PERMISSION_SET_MODERATOR = 'set-moderator';
|
||||
const PERMISSION_REMOVE_USER = 'remove-user';
|
||||
|
||||
class RoomMembersView extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
|
@ -43,7 +49,12 @@ class RoomMembersView extends React.Component {
|
|||
showActionSheet: PropTypes.func,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
useRealName: PropTypes.bool
|
||||
useRealName: PropTypes.bool,
|
||||
muteUserPermission: PropTypes.array,
|
||||
setLeaderPermission: PropTypes.array,
|
||||
setOwnerPermission: PropTypes.array,
|
||||
setModeratorPermission: PropTypes.array,
|
||||
removeUserPermission: PropTypes.array
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -81,7 +92,20 @@ class RoomMembersView extends React.Component {
|
|||
this.fetchMembers();
|
||||
|
||||
const { room } = this.state;
|
||||
this.permissions = await RocketChat.hasPermission(['mute-user', 'set-leader', 'set-owner', 'set-moderator', 'remove-user'], room.rid);
|
||||
const {
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission
|
||||
} = this.props;
|
||||
const result = await RocketChat.hasPermission([
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission
|
||||
], room.rid);
|
||||
|
||||
this.permissions = {
|
||||
[PERMISSION_MUTE_USER]: result[0],
|
||||
[PERMISSION_SET_LEADER]: result[1],
|
||||
[PERMISSION_SET_OWNER]: result[2],
|
||||
[PERMISSION_SET_MODERATOR]: result[3],
|
||||
[PERMISSION_REMOVE_USER]: result[4]
|
||||
};
|
||||
|
||||
const hasSinglePermission = Object.values(this.permissions).some(p => !!p);
|
||||
if (hasSinglePermission) {
|
||||
|
@ -452,7 +476,12 @@ const mapStateToProps = state => ({
|
|||
baseUrl: state.server.server,
|
||||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
useRealName: state.settings.UI_Use_Real_Name
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
muteUserPermission: state.permissions[PERMISSION_MUTE_USER],
|
||||
setLeaderPermission: state.permissions[PERMISSION_SET_LEADER],
|
||||
setOwnerPermission: state.permissions[PERMISSION_SET_OWNER],
|
||||
setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR],
|
||||
removeUserPermission: state.permissions[PERMISSION_REMOVE_USER]
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView)));
|
||||
|
|
|
@ -436,10 +436,7 @@ class RoomView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
// We run `canAutoTranslate` again in order to refetch auto translate permission
|
||||
// in case of a missing connection or poor connection on room open
|
||||
const canAutoTranslate = await RocketChat.canAutoTranslate();
|
||||
|
||||
const canAutoTranslate = RocketChat.canAutoTranslate();
|
||||
const member = await this.getRoomMember();
|
||||
|
||||
this.setState({ canAutoTranslate, member, loading: false });
|
||||
|
|
|
@ -4,19 +4,16 @@ import {
|
|||
ScrollView, Text, View, TouchableWithoutFeedback
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import isEqual from 'react-fast-compare';
|
||||
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import Status from '../../containers/Status/Status';
|
||||
import log, { logEvent, events } from '../../utils/log';
|
||||
import { logEvent, events } from '../../utils/log';
|
||||
import I18n from '../../i18n';
|
||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import styles from './styles';
|
||||
import SidebarItem from './SidebarItem';
|
||||
import { themes } from '../../constants/colors';
|
||||
import database from '../../lib/database';
|
||||
import { withTheme } from '../../theme';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
|
@ -27,13 +24,6 @@ Separator.propTypes = {
|
|||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
const permissions = [
|
||||
'view-statistics',
|
||||
'view-room-administration',
|
||||
'view-user-administration',
|
||||
'view-privileged-setting'
|
||||
];
|
||||
|
||||
class Sidebar extends Component {
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
|
@ -45,32 +35,24 @@ class Sidebar extends Component {
|
|||
loadingServer: PropTypes.bool,
|
||||
useRealName: PropTypes.bool,
|
||||
allowStatusMessage: PropTypes.bool,
|
||||
isMasterDetail: PropTypes.bool
|
||||
isMasterDetail: PropTypes.bool,
|
||||
viewStatisticsPermission: PropTypes.object,
|
||||
viewRoomAdministrationPermission: PropTypes.object,
|
||||
viewUserAdministrationPermission: PropTypes.object,
|
||||
viewPrivilegedSettingPermission: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showStatus: false,
|
||||
isAdmin: false
|
||||
showStatus: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setIsAdmin();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const { loadingServer } = this.props;
|
||||
if (loadingServer && nextProps.loadingServer !== loadingServer) {
|
||||
this.setIsAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { showStatus, isAdmin } = this.state;
|
||||
const {
|
||||
Site_Name, user, baseUrl, state, isMasterDetail, useRealName, theme
|
||||
Site_Name, user, baseUrl, state, isMasterDetail, useRealName, theme, viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission
|
||||
} = this.props;
|
||||
// Drawer navigation state
|
||||
if (state?.index !== nextProps.state?.index) {
|
||||
|
@ -103,25 +85,42 @@ class Sidebar extends Component {
|
|||
if (nextState.isAdmin !== isAdmin) {
|
||||
return true;
|
||||
}
|
||||
if (!isEqual(nextProps.viewStatisticsPermission, viewStatisticsPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!isEqual(nextProps.viewRoomAdministrationPermission, viewRoomAdministrationPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!isEqual(nextProps.viewUserAdministrationPermission, viewUserAdministrationPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!isEqual(nextProps.viewPrivilegedSettingPermission, viewPrivilegedSettingPermission)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async setIsAdmin() {
|
||||
const db = database.active;
|
||||
const { user } = this.props;
|
||||
|
||||
getIsAdmin() {
|
||||
const {
|
||||
user, viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission
|
||||
} = this.props;
|
||||
const { roles } = user;
|
||||
try {
|
||||
if (roles) {
|
||||
const permissionsCollection = db.collections.get('permissions');
|
||||
const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch();
|
||||
const isAdmin = permissionsFiltered.reduce((result, permission) => (
|
||||
result || permission.roles.some(r => roles.indexOf(r) !== -1)),
|
||||
false);
|
||||
this.setState({ isAdmin });
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
const allPermissions = [viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission];
|
||||
let isAdmin = false;
|
||||
|
||||
if (roles) {
|
||||
isAdmin = allPermissions.reduce((result, permission) => {
|
||||
if (permission) {
|
||||
return (
|
||||
result || permission.some(r => roles.indexOf(r) !== -1)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
}
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
sidebarNavigate = (route) => {
|
||||
|
@ -143,9 +142,8 @@ class Sidebar extends Component {
|
|||
}
|
||||
|
||||
renderAdmin = () => {
|
||||
const { isAdmin } = this.state;
|
||||
const { theme, isMasterDetail } = this.props;
|
||||
if (!isAdmin) {
|
||||
if (!this.getIsAdmin()) {
|
||||
return null;
|
||||
}
|
||||
const routeName = isMasterDetail ? 'AdminPanelView' : 'AdminPanelStackNavigator';
|
||||
|
@ -275,7 +273,11 @@ const mapStateToProps = state => ({
|
|||
loadingServer: state.server.loading,
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
allowStatusMessage: state.settings.Accounts_AllowUserStatusMessageChange,
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
viewStatisticsPermission: state.permissions['view-statistics'],
|
||||
viewRoomAdministrationPermission: state.permissions['view-room-administration'],
|
||||
viewUserAdministrationPermission: state.permissions['view-user-administration'],
|
||||
viewPrivilegedSettingPermission: state.permissions['view-privileged-setting']
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(Sidebar));
|
||||
|
|
Loading…
Reference in New Issue