From 8fd561c37a7f47e124c002f23e69339519f784cc Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 20 Nov 2017 08:39:42 -0200 Subject: [PATCH 1/3] - Permissions schema - Permissions call --- app/lib/realm.js | 21 ++++++++++++++++++++- app/lib/rocketchat.js | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/app/lib/realm.js b/app/lib/realm.js index 72481b5ee..39c243598 100644 --- a/app/lib/realm.js +++ b/app/lib/realm.js @@ -22,6 +22,23 @@ const settingsSchema = { } }; +const permissionsRolesSchema = { + name: 'permissionsRoles', + properties: { + value: 'string' + } +}; + +const permissionsSchema = { + name: 'permissions', + primaryKey: '_id', + properties: { + _id: 'string', + _server: 'servers', + roles: { type: 'list', objectType: 'permissionsRoles' } + } +}; + const roomsSchema = { name: 'rooms', primaryKey: '_id', @@ -128,7 +145,9 @@ const realm = new Realm({ usersSchema, roomsSchema, attachment, - messagesEditedBySchema + messagesEditedBySchema, + permissionsSchema, + permissionsRolesSchema ] }); export default realm; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 471f56490..6adc45303 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -83,6 +83,29 @@ const RocketChat = { reduxStore.dispatch(actions.setAllSettings(settings)); }); + Meteor.call('permissions/get', (err, data) => { + if (err) { + console.error(err); + } + + const permissions = {}; + realm.write(() => { + data.forEach((item) => { + const permission = { + _id: item._id, + roles: [] + }; + permission._server = { id: reduxStore.getState().server.server }; + item.roles.forEach((role) => { + permission.roles.push({ value: role }); + }); + realm.create('permissions', permission, true); + permissions[item._id] = permission; + }); + }); + // reduxStore.dispatch(actions.setAllPermissions(permissions)); + }); + Meteor.ddp.on('changed', (ddbMessage) => { if (ddbMessage.collection === 'stream-room-messages') { realm.write(() => { From 273265c0354654d4dca48231683d6501957de7d5 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 20 Nov 2017 09:09:40 -0200 Subject: [PATCH 2/3] Permissions reducer --- app/actions/index.js | 6 ++++++ app/constants/types.js | 1 + app/lib/rocketchat.js | 2 +- app/reducers/index.js | 4 ++-- app/reducers/permissions.js | 17 +++++++++++++++++ 5 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 app/reducers/permissions.js diff --git a/app/actions/index.js b/app/actions/index.js index dba8b7e18..5c70e290b 100644 --- a/app/actions/index.js +++ b/app/actions/index.js @@ -25,6 +25,12 @@ export function setAllSettings(settings) { payload: settings }; } +export function setAllPermissions(permissions) { + return { + type: types.SET_ALL_PERMISSIONS, + payload: permissions + }; +} export function login() { return { type: 'LOGIN' diff --git a/app/constants/types.js b/app/constants/types.js index f772c2b92..0ac33098d 100644 --- a/app/constants/types.js +++ b/app/constants/types.js @@ -1,2 +1,3 @@ export const SET_CURRENT_SERVER = 'SET_CURRENT_SERVER'; export const SET_ALL_SETTINGS = 'SET_ALL_SETTINGS'; +export const SET_ALL_PERMISSIONS = 'SET_ALL_PERMISSIONS'; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 6adc45303..1b53eb861 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -103,7 +103,7 @@ const RocketChat = { permissions[item._id] = permission; }); }); - // reduxStore.dispatch(actions.setAllPermissions(permissions)); + reduxStore.dispatch(actions.setAllPermissions(permissions)); }); Meteor.ddp.on('changed', (ddbMessage) => { diff --git a/app/reducers/index.js b/app/reducers/index.js index 3321b8481..723437b69 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -7,8 +7,8 @@ import server from './server'; import navigator from './navigator'; import createChannel from './createChannel'; import app from './app'; - +import permissions from './permissions'; export default combineReducers({ - settings, login, meteor, messages, server, navigator, createChannel, app + settings, login, meteor, messages, server, navigator, createChannel, app, permissions }); diff --git a/app/reducers/permissions.js b/app/reducers/permissions.js new file mode 100644 index 000000000..c683eb72e --- /dev/null +++ b/app/reducers/permissions.js @@ -0,0 +1,17 @@ +import * as types from '../constants/types'; + +const initialState = { + settings: {} +}; + +export default function settings(state = initialState, action) { + switch (action.type) { + case types.SET_ALL_PERMISSIONS: + return { + ...state, + ...action.payload + }; + default: + return state; + } +} From 59f4e292a98215e9eb04aa441cc97bbc0f9b56e9 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 20 Nov 2017 12:40:50 -0200 Subject: [PATCH 3/3] getRoomRoles --- app/actions/actionsTypes.js | 1 + app/actions/roomRoles.js | 20 +++++++++++ app/containers/message/index.js | 61 ++++++++++++++++++++++++++------- app/lib/rocketchat.js | 3 ++ app/reducers/messages.js | 6 ++++ app/reducers/roomRoles.js | 33 ++++++++++++++++++ 6 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 app/actions/roomRoles.js create mode 100644 app/reducers/roomRoles.js diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 29a0dd0be..6a556d555 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -27,6 +27,7 @@ export const FORGOT_PASSWORD = createRequestTypes('FORGOT_PASSWORD', [ 'INIT' ]); export const ROOMS = createRequestTypes('ROOMS'); +export const ROOM_ROLES = createRequestTypes('ROOM_ROLES'); export const APP = createRequestTypes('APP', ['READY', 'INIT']); export const MESSAGES = createRequestTypes('MESSAGES', [ ...defaultTypes, diff --git a/app/actions/roomRoles.js b/app/actions/roomRoles.js new file mode 100644 index 000000000..8ce5a2e42 --- /dev/null +++ b/app/actions/roomRoles.js @@ -0,0 +1,20 @@ +import * as types from './actionsTypes'; + +export function roomRolesRequest() { + return { + type: types.ROOM_ROLES.REQUEST + }; +} + +export function roomRolesSuccess(roles) { + return { + type: types.ROOM_ROLES.SUCCESS, + roles + }; +} + +export function roomRolesFailure() { + return { + type: types.ROOM_ROLES.FAILURE + }; +} diff --git a/app/containers/message/index.js b/app/containers/message/index.js index 444c8f6d0..08788ab25 100644 --- a/app/containers/message/index.js +++ b/app/containers/message/index.js @@ -5,6 +5,7 @@ import { emojify } from 'react-emojione'; import Markdown from 'react-native-easy-markdown'; // eslint-disable-line import ActionSheet from 'react-native-actionsheet'; import { connect } from 'react-redux'; +import * as moment from 'moment'; import Card from './Card'; import User from './User'; @@ -19,11 +20,6 @@ import { } from '../../actions/messages'; import RocketChat from '../../lib/rocketchat'; -const title = 'Message actions'; -const options = ['Cancel', 'Reply', 'Edit', 'Permalink', 'Copy', 'Quote', 'Star Message', 'Pin Message', 'Delete']; -const CANCEL_INDEX = 0; -const DESTRUCTIVE_INDEX = 8; - const styles = StyleSheet.create({ content: { flexGrow: 1, @@ -48,7 +44,10 @@ const styles = StyleSheet.create({ @connect(state => ({ message: state.messages.message, permalink: state.messages.permalink, - user: state.login.user + user: state.login.user, + permissions: state.permissions, + Message_AllowEditing: state.settings.Message_AllowEditing, + Message_AllowEditing_BlockEditInMinutes: state.settings.Message_AllowEditing_BlockEditInMinutes }), dispatch => ({ deleteRequest: message => dispatch(deleteRequest(message)), editInit: message => dispatch(editInit(message)), @@ -69,6 +68,9 @@ export default class Message extends React.Component { togglePinRequest: PropTypes.func.isRequired, setInput: PropTypes.func.isRequired, user: PropTypes.object.isRequired, + permissions: PropTypes.object.isRequired, + Message_AllowEditing: PropTypes.bool, + Message_AllowEditing_BlockEditInMinutes: PropTypes.number, message: PropTypes.object, permalink: PropTypes.string } @@ -82,6 +84,16 @@ export default class Message extends React.Component { }; this.handleActionPress = this.handleActionPress.bind(this); this.showActions = this.showActions.bind(this); + + // this.options = ['Cancel', 'Reply', 'Edit', 'Permalink', 'Copy', 'Quote', 'Star Message', 'Pin Message', 'Delete']; + this.CANCEL_INDEX = 0; + this.options = ['Cancel']; + this.options.push('Reply'); + if (this.allowEdit()) { + this.addButton('Edit'); + } + this.options.push('Delete'); + this.DESTRUCTIVE_INDEX = this.options.length - 1; } async componentWillReceiveProps(nextProps) { @@ -113,6 +125,32 @@ export default class Message extends React.Component { } } + addButton = () => { + this.options.push('Edit'); + } + + allowEdit = () => { + const hasPermission = this.props.permissions['edit-message']; + const isEditAllowed = this.props.Message_AllowEditing; + const editOwn = this.props.item.u && this.props.item.u._id === this.props.user.id; + if (!(hasPermission || (isEditAllowed && editOwn))) { + return false; + } + const blockEditInMinutes = this.props.Message_AllowEditing_BlockEditInMinutes; + if (blockEditInMinutes) { + let msgTs; + if (this.props.item.ts != null) { + msgTs = moment(this.props.item.ts); + } + let currentTsDiff; + if (msgTs != null) { + currentTsDiff = moment().diff(msgTs, 'minutes'); + } + return currentTsDiff < blockEditInMinutes; + } + return true; + } + isDeleted() { return !this.props.item.msg; } @@ -206,9 +244,6 @@ export default class Message extends React.Component { // delete } else if (actionIndex === 8) { this.handleDelete(); - // reply - } else { - console.log(actionIndex, this.props.item); } } @@ -262,10 +297,10 @@ export default class Message extends React.Component { this.ActionSheet = o} - title={title} - options={options} - cancelButtonIndex={CANCEL_INDEX} - destructiveButtonIndex={DESTRUCTIVE_INDEX} + title='Messages actions' + options={this.options} + cancelButtonIndex={this.CANCEL_INDEX} + destructiveButtonIndex={this.DESTRUCTIVE_INDEX} onPress={this.handleActionPress} /> diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 1b53eb861..c0fc2ea62 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -506,6 +506,9 @@ const RocketChat = { return resolve(result[0]); }); }, + getRoomRoles(rid) { + return call('getRoomRoles', { rid }); + }, async getPermalink(message) { return new Promise(async(resolve, reject) => { let room; diff --git a/app/reducers/messages.js b/app/reducers/messages.js index a2363bdca..6ef193baf 100644 --- a/app/reducers/messages.js +++ b/app/reducers/messages.js @@ -39,6 +39,12 @@ export default function messages(state = initialState, action) { message: {}, editing: false }; + case types.MESSAGES.EDIT_FAILURE: + return { + ...state, + message: {}, + editing: false + }; case types.MESSAGES.PERMALINK_SUCCESS: return { ...state, diff --git a/app/reducers/roomRoles.js b/app/reducers/roomRoles.js new file mode 100644 index 000000000..04a33bec3 --- /dev/null +++ b/app/reducers/roomRoles.js @@ -0,0 +1,33 @@ +import * as types from '../actions/actionsTypes'; + +const initialState = { + isFetching: false, + failure: false, + roles: [] +}; + +export default function login(state = initialState, action) { + switch (action.type) { + case types.ROOM_ROLES.REQUEST: + return { + ...state, + isFetching: true, + roles: [] + }; + case types.ROOM_ROLES.SUCCESS: + return { + ...state, + isFetching: false, + roles: action.roles + }; + case types.ROOM_ROLES.FAILURE: + return { + ...state, + isFetching: false, + failure: true, + roles: [] + }; + default: + return state; + } +}