Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions app/actions/permissions.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { Action } from 'redux';

import { IPermissions } from '../reducers/permissions';
import { IPermissionsState, TSupportedPermissions } from '../reducers/permissions';
import { PERMISSIONS } from './actionsTypes';

interface ISetPermissions extends Action {
permissions: IPermissions;
permissions: IPermissionsState;
}

interface IUpdatePermissions extends Action {
payload: { id: string; roles: string };
payload: { id: TSupportedPermissions; roles: string[] };
}

export type TActionPermissions = ISetPermissions & IUpdatePermissions;

export function setPermissions(permissions: IPermissions): ISetPermissions {
export function setPermissions(permissions: IPermissionsState): ISetPermissions {
return {
type: PERMISSIONS.SET,
permissions
};
}

export function updatePermission(id: string, roles: string): IUpdatePermissions {
export function updatePermission(id: TSupportedPermissions, roles: string[]): IUpdatePermissions {
return {
type: PERMISSIONS.UPDATE,
payload: { id, roles }
Expand Down
4 changes: 2 additions & 2 deletions app/definitions/IPermission.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Model from '@nozbe/watermelondb/Model';

export interface IPermission {
id: string;
_id: string;
roles: string[];
_updatedAt: Date;
_updatedAt: Date | string;
}

export type TPermissionModel = IPermission & Model;
7 changes: 5 additions & 2 deletions app/definitions/redux/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { IActionSettings } from '../../actions/settings';
import { TActionsShare } from '../../actions/share';
import { TActionSortPreferences } from '../../actions/sortPreferences';
import { TActionUserTyping } from '../../actions/usersTyping';
import { TActionPermissions } from '../../actions/permissions';
import { TActionEnterpriseModules } from '../../actions/enterpriseModules';
// REDUCERS
import { IActiveUsers } from '../../reducers/activeUsers';
import { IApp } from '../../reducers/app';
Expand All @@ -26,8 +28,8 @@ import { ISelectedUsers } from '../../reducers/selectedUsers';
import { IServer } from '../../reducers/server';
import { ISettings } from '../../reducers/settings';
import { IShare } from '../../reducers/share';
import { IPermissionsState } from '../../reducers/permissions';
import { IEnterpriseModules } from '../../reducers/enterpriseModules';
import { TActionEnterpriseModules } from '../../actions/enterpriseModules';

export interface IApplicationState {
settings: ISettings;
Expand All @@ -49,7 +51,7 @@ export interface IApplicationState {
inquiry: any;
enterpriseModules: IEnterpriseModules;
encryption: IEncryption;
permissions: any;
permissions: IPermissionsState;
roles: IRoles;
}

Expand All @@ -67,4 +69,5 @@ export type TApplicationActions = TActionActiveUsers &
TActionsShare &
TActionServer &
TActionApp &
TActionPermissions &
TActionEnterpriseModules;
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import database from '../database';
import log from '../../utils/log';
import { store as reduxStore } from '../auxStore';
import RocketChat from '../rocketchat';
import sdk from '../rocketchat/services/sdk';
import { setPermissions as setPermissionsAction } from '../../actions/permissions';
import protectedFunction from './helpers/protectedFunction';
import { TPermissionModel, IPermission } from '../../definitions';

const PERMISSIONS = [
export const SUPPORTED_PERMISSIONS = [
'add-user-to-any-c-room',
'add-user-to-any-p-room',
'add-user-to-joined-room',
Expand Down Expand Up @@ -57,18 +59,20 @@ const PERMISSIONS = [
'edit-livechat-room-customfields',
'view-canned-responses',
'mobile-upload-file'
];
] as const;

export async function setPermissions() {
export async function setPermissions(): Promise<void> {
const db = database.active;
const permissionsCollection = db.get('permissions');
const allPermissions = await permissionsCollection.query(Q.where('id', Q.oneOf(PERMISSIONS))).fetch();
const allPermissions = await permissionsCollection
.query(Q.where('id', Q.oneOf(SUPPORTED_PERMISSIONS as unknown as string[])))
.fetch();
const parsed = allPermissions.reduce((acc, item) => ({ ...acc, [item.id]: item.roles }), {});

reduxStore.dispatch(setPermissionsAction(parsed));
}

const getUpdatedSince = allRecords => {
const getUpdatedSince = (allRecords: TPermissionModel[]) => {
try {
if (!allRecords.length) {
return null;
Expand All @@ -78,57 +82,63 @@ const getUpdatedSince = allRecords => {
['_updatedAt'],
['desc']
);
return ordered && ordered[0]._updatedAt.toISOString();
return new Date(ordered[0]._updatedAt).toISOString();
} catch (e) {
log(e);
}
return null;
};

const updatePermissions = async ({ update = [], remove = [], allRecords }) => {
const updatePermissions = async ({
update = [],
remove = [],
allRecords
}: {
update?: IPermission[];
remove?: IPermission[];
allRecords: TPermissionModel[];
}) => {
if (!((update && update.length) || (remove && remove.length))) {
return;
}
const db = database.active;
const permissionsCollection = db.get('permissions');

// filter permissions
let permissionsToCreate = [];
let permissionsToUpdate = [];
let permissionsToDelete = [];
const batch: TPermissionModel[] = [];

// Delete
if (remove?.length) {
const filteredPermissionsToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
const permissionsToDelete = filteredPermissionsToDelete.map(permission => permission.prepareDestroyPermanently());
batch.push(...permissionsToDelete);
}

// Create or update
if (update && update.length) {
permissionsToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
permissionsToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
permissionsToCreate = permissionsToCreate.map(permission =>
if (update?.length) {
const filteredPermissionsToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
const filteredPermissionsToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
const permissionsToCreate = filteredPermissionsToCreate.map(permission =>
permissionsCollection.prepareCreate(
protectedFunction(p => {
protectedFunction((p: TPermissionModel) => {
p._raw = sanitizedRaw({ id: permission._id }, permissionsCollection.schema);
Object.assign(p, permission);
})
)
);
permissionsToUpdate = permissionsToUpdate.map(permission => {
const permissionsToUpdate = filteredPermissionsToUpdate.map(permission => {
const newPermission = update.find(p => p._id === permission.id);
return permission.prepareUpdate(
protectedFunction(p => {
protectedFunction((p: TPermissionModel) => {
Object.assign(p, newPermission);
})
);
});
}

// Delete
if (remove && remove.length) {
permissionsToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
permissionsToDelete = permissionsToDelete.map(permission => permission.prepareDestroyPermanently());
batch.push(...permissionsToCreate, ...permissionsToUpdate);
}

const batch = [...permissionsToCreate, ...permissionsToUpdate, ...permissionsToDelete];

try {
await db.action(async () => {
await db.write(async () => {
await db.batch(...batch);
});
return true;
Expand All @@ -137,18 +147,19 @@ const updatePermissions = async ({ update = [], remove = [], allRecords }) => {
}
};

export function getPermissions() {
export function getPermissions(): Promise<void> {
return new Promise(async resolve => {
try {
const serverVersion = reduxStore.getState().server.version;
const serverVersion: string | null = reduxStore.getState().server.version;
const db = database.active;
const permissionsCollection = db.get('permissions');
const allRecords = await permissionsCollection.query().fetch();
RocketChat.subscribe('stream-notify-logged', 'permissions-changed');
// if server version is lower than 0.73.0, fetches from old api
if (compareServerVersion(serverVersion, 'lowerThan', '0.73.0')) {
if (serverVersion && compareServerVersion(serverVersion, 'lowerThan', '0.73.0')) {
// RC 0.66.0
const result = await this.sdk.get('permissions.list');
// @ts-ignore
const result: any = await sdk.get('permissions.list');
if (!result.success) {
return resolve();
}
Expand All @@ -157,25 +168,25 @@ export function getPermissions() {
setPermissions();
}
return resolve();
} else {
const params = {};
const updatedSince = getUpdatedSince(allRecords);
if (updatedSince) {
params.updatedSince = updatedSince;
}
// RC 0.73.0
const result = await this.sdk.get('permissions.listAll', params);
}

if (!result.success) {
return resolve();
}
const params: { updatedSince?: string } = {};
const updatedSince = getUpdatedSince(allRecords);
if (updatedSince) {
params.updatedSince = updatedSince;
}
// RC 0.73.0
const result = await sdk.get('permissions.listAll', params);

const changePermissions = await updatePermissions({ update: result.update, remove: result.delete, allRecords });
if (changePermissions) {
setPermissions();
}
if (!result.success) {
return resolve();
}

const changePermissions = await updatePermissions({ update: result.update, remove: result.remove, allRecords });
if (changePermissions) {
setPermissions();
}
return resolve();
} catch (e) {
log(e);
return resolve();
Expand Down
8 changes: 4 additions & 4 deletions app/reducers/permissions.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { setPermissions, updatePermission } from '../actions/permissions';
import { mockedStore } from './mockedStore';
import { initialState } from './permissions';
import { initialState, IPermissionsState } from './permissions';

describe('test permissions reducer', () => {
it('should return initial state', () => {
Expand All @@ -9,15 +9,15 @@ describe('test permissions reducer', () => {
});

it('should return modified store after setPermissions', () => {
const permissions = { hasEditPermission: 'enabled', hasForceDeletePermission: 'enabled' };
const permissions: IPermissionsState = { 'add-user-to-any-c-room': ['admin'], 'add-team-channel': ['user'] };
mockedStore.dispatch(setPermissions(permissions));
const state = mockedStore.getState().permissions;
expect(state).toEqual(permissions);
});

it('should return empty store after remove user', () => {
mockedStore.dispatch(updatePermission('hasEditPermission', 'disabled'));
mockedStore.dispatch(updatePermission('add-team-channel', ['owner']));
const state = mockedStore.getState().permissions;
expect(state.hasEditPermission).toEqual('disabled');
expect(state['add-team-channel']).toEqual(['owner']);
});
});
11 changes: 8 additions & 3 deletions app/reducers/permissions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { PERMISSIONS } from '../actions/actionsTypes';
import { TActionPermissions } from '../actions/permissions';
import { SUPPORTED_PERMISSIONS } from '../lib/methods/getPermissions';

export type IPermissions = Record<string, string>;
export type TSupportedPermissions = typeof SUPPORTED_PERMISSIONS[number];

export const initialState: IPermissions = {};
export type IPermissionsState = {
[K in TSupportedPermissions]?: string[];
};

export default function permissions(state = initialState, action: TActionPermissions): IPermissions {
export const initialState: IPermissionsState = {};

export default function permissions(state = initialState, action: TActionPermissions): IPermissionsState {
switch (action.type) {
case PERMISSIONS.SET:
return action.permissions;
Expand Down
4 changes: 2 additions & 2 deletions app/views/CreateChannelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ interface ICreateChannelViewProps extends IBaseScreen<ChatsStackParamList, 'Crea
roles: string[];
};
teamId: string;
createPublicChannelPermission: string[];
createPrivateChannelPermission: string[];
createPublicChannelPermission: string[] | undefined;
createPrivateChannelPermission: string[] | undefined;
}

interface ISwitch extends SwitchProps {
Expand Down
4 changes: 2 additions & 2 deletions app/views/LivechatEditView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ interface ILivechatEditViewProps {
navigation: StackNavigationProp<ChatsStackParamList, 'LivechatEditView'>;
route: RouteProp<ChatsStackParamList, 'LivechatEditView'>;
theme: string;
editOmnichannelContact: string[];
editLivechatRoomCustomfields: string[];
editOmnichannelContact: string[] | undefined;
editLivechatRoomCustomfields: string[] | undefined;
}

const Title = ({ title, theme }: ITitle) =>
Expand Down
10 changes: 5 additions & 5 deletions app/views/NewMessageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ interface INewMessageViewProps extends IBaseScreen<any, 'NewMessageView'> {
maxUsers: number;
isMasterDetail: boolean;
serverVersion: string;
createTeamPermission: string[];
createDirectMessagePermission: string[];
createPublicChannelPermission: string[];
createPrivateChannelPermission: string[];
createDiscussionPermission: string[];
createTeamPermission: string[] | undefined;
createDirectMessagePermission: string[] | undefined;
createPublicChannelPermission: string[] | undefined;
createPrivateChannelPermission: string[] | undefined;
createDiscussionPermission: string[] | undefined;
}

class NewMessageView extends React.Component<INewMessageViewProps, INewMessageViewState> {
Expand Down