Chore: Migrate getPermissions to Typescript (#3720)
* Migrating... * Fix IPermission * Playing with types * Remove `as const` * Fix lint * Fix test * Apply sdk * Fix lint and autocomplete
This commit is contained in:
parent
86cc8a7d16
commit
a58b27e4f1
|
@ -1,26 +1,26 @@
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
|
|
||||||
import { IPermissions } from '../reducers/permissions';
|
import { IPermissionsState, TSupportedPermissions } from '../reducers/permissions';
|
||||||
import { PERMISSIONS } from './actionsTypes';
|
import { PERMISSIONS } from './actionsTypes';
|
||||||
|
|
||||||
interface ISetPermissions extends Action {
|
interface ISetPermissions extends Action {
|
||||||
permissions: IPermissions;
|
permissions: IPermissionsState;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IUpdatePermissions extends Action {
|
interface IUpdatePermissions extends Action {
|
||||||
payload: { id: string; roles: string };
|
payload: { id: TSupportedPermissions; roles: string[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TActionPermissions = ISetPermissions & IUpdatePermissions;
|
export type TActionPermissions = ISetPermissions & IUpdatePermissions;
|
||||||
|
|
||||||
export function setPermissions(permissions: IPermissions): ISetPermissions {
|
export function setPermissions(permissions: IPermissionsState): ISetPermissions {
|
||||||
return {
|
return {
|
||||||
type: PERMISSIONS.SET,
|
type: PERMISSIONS.SET,
|
||||||
permissions
|
permissions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updatePermission(id: string, roles: string): IUpdatePermissions {
|
export function updatePermission(id: TSupportedPermissions, roles: string[]): IUpdatePermissions {
|
||||||
return {
|
return {
|
||||||
type: PERMISSIONS.UPDATE,
|
type: PERMISSIONS.UPDATE,
|
||||||
payload: { id, roles }
|
payload: { id, roles }
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Model from '@nozbe/watermelondb/Model';
|
import Model from '@nozbe/watermelondb/Model';
|
||||||
|
|
||||||
export interface IPermission {
|
export interface IPermission {
|
||||||
id: string;
|
_id: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
_updatedAt: Date;
|
_updatedAt: Date | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TPermissionModel = IPermission & Model;
|
export type TPermissionModel = IPermission & Model;
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { IActionSettings } from '../../actions/settings';
|
||||||
import { TActionsShare } from '../../actions/share';
|
import { TActionsShare } from '../../actions/share';
|
||||||
import { TActionSortPreferences } from '../../actions/sortPreferences';
|
import { TActionSortPreferences } from '../../actions/sortPreferences';
|
||||||
import { TActionUserTyping } from '../../actions/usersTyping';
|
import { TActionUserTyping } from '../../actions/usersTyping';
|
||||||
|
import { TActionPermissions } from '../../actions/permissions';
|
||||||
|
import { TActionEnterpriseModules } from '../../actions/enterpriseModules';
|
||||||
// REDUCERS
|
// REDUCERS
|
||||||
import { IActiveUsers } from '../../reducers/activeUsers';
|
import { IActiveUsers } from '../../reducers/activeUsers';
|
||||||
import { IApp } from '../../reducers/app';
|
import { IApp } from '../../reducers/app';
|
||||||
|
@ -26,8 +28,8 @@ import { ISelectedUsers } from '../../reducers/selectedUsers';
|
||||||
import { IServer } from '../../reducers/server';
|
import { IServer } from '../../reducers/server';
|
||||||
import { ISettings } from '../../reducers/settings';
|
import { ISettings } from '../../reducers/settings';
|
||||||
import { IShare } from '../../reducers/share';
|
import { IShare } from '../../reducers/share';
|
||||||
|
import { IPermissionsState } from '../../reducers/permissions';
|
||||||
import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
||||||
import { TActionEnterpriseModules } from '../../actions/enterpriseModules';
|
|
||||||
|
|
||||||
export interface IApplicationState {
|
export interface IApplicationState {
|
||||||
settings: ISettings;
|
settings: ISettings;
|
||||||
|
@ -49,7 +51,7 @@ export interface IApplicationState {
|
||||||
inquiry: any;
|
inquiry: any;
|
||||||
enterpriseModules: IEnterpriseModules;
|
enterpriseModules: IEnterpriseModules;
|
||||||
encryption: IEncryption;
|
encryption: IEncryption;
|
||||||
permissions: any;
|
permissions: IPermissionsState;
|
||||||
roles: IRoles;
|
roles: IRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,4 +69,5 @@ export type TApplicationActions = TActionActiveUsers &
|
||||||
TActionsShare &
|
TActionsShare &
|
||||||
TActionServer &
|
TActionServer &
|
||||||
TActionApp &
|
TActionApp &
|
||||||
|
TActionPermissions &
|
||||||
TActionEnterpriseModules;
|
TActionEnterpriseModules;
|
||||||
|
|
|
@ -7,10 +7,12 @@ import database from '../database';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import { store as reduxStore } from '../auxStore';
|
import { store as reduxStore } from '../auxStore';
|
||||||
import RocketChat from '../rocketchat';
|
import RocketChat from '../rocketchat';
|
||||||
|
import sdk from '../rocketchat/services/sdk';
|
||||||
import { setPermissions as setPermissionsAction } from '../../actions/permissions';
|
import { setPermissions as setPermissionsAction } from '../../actions/permissions';
|
||||||
import protectedFunction from './helpers/protectedFunction';
|
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-c-room',
|
||||||
'add-user-to-any-p-room',
|
'add-user-to-any-p-room',
|
||||||
'add-user-to-joined-room',
|
'add-user-to-joined-room',
|
||||||
|
@ -57,18 +59,20 @@ const PERMISSIONS = [
|
||||||
'edit-livechat-room-customfields',
|
'edit-livechat-room-customfields',
|
||||||
'view-canned-responses',
|
'view-canned-responses',
|
||||||
'mobile-upload-file'
|
'mobile-upload-file'
|
||||||
];
|
] as const;
|
||||||
|
|
||||||
export async function setPermissions() {
|
export async function setPermissions(): Promise<void> {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const permissionsCollection = db.get('permissions');
|
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 }), {});
|
const parsed = allPermissions.reduce((acc, item) => ({ ...acc, [item.id]: item.roles }), {});
|
||||||
|
|
||||||
reduxStore.dispatch(setPermissionsAction(parsed));
|
reduxStore.dispatch(setPermissionsAction(parsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUpdatedSince = allRecords => {
|
const getUpdatedSince = (allRecords: TPermissionModel[]) => {
|
||||||
try {
|
try {
|
||||||
if (!allRecords.length) {
|
if (!allRecords.length) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -78,57 +82,63 @@ const getUpdatedSince = allRecords => {
|
||||||
['_updatedAt'],
|
['_updatedAt'],
|
||||||
['desc']
|
['desc']
|
||||||
);
|
);
|
||||||
return ordered && ordered[0]._updatedAt.toISOString();
|
return new Date(ordered[0]._updatedAt).toISOString();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
return null;
|
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))) {
|
if (!((update && update.length) || (remove && remove.length))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const permissionsCollection = db.get('permissions');
|
const permissionsCollection = db.get('permissions');
|
||||||
|
|
||||||
// filter permissions
|
const batch: TPermissionModel[] = [];
|
||||||
let permissionsToCreate = [];
|
|
||||||
let permissionsToUpdate = [];
|
// Delete
|
||||||
let permissionsToDelete = [];
|
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
|
// Create or update
|
||||||
if (update && update.length) {
|
if (update?.length) {
|
||||||
permissionsToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
|
const filteredPermissionsToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
|
||||||
permissionsToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
|
const filteredPermissionsToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
|
||||||
permissionsToCreate = permissionsToCreate.map(permission =>
|
const permissionsToCreate = filteredPermissionsToCreate.map(permission =>
|
||||||
permissionsCollection.prepareCreate(
|
permissionsCollection.prepareCreate(
|
||||||
protectedFunction(p => {
|
protectedFunction((p: TPermissionModel) => {
|
||||||
p._raw = sanitizedRaw({ id: permission._id }, permissionsCollection.schema);
|
p._raw = sanitizedRaw({ id: permission._id }, permissionsCollection.schema);
|
||||||
Object.assign(p, permission);
|
Object.assign(p, permission);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
permissionsToUpdate = permissionsToUpdate.map(permission => {
|
const permissionsToUpdate = filteredPermissionsToUpdate.map(permission => {
|
||||||
const newPermission = update.find(p => p._id === permission.id);
|
const newPermission = update.find(p => p._id === permission.id);
|
||||||
return permission.prepareUpdate(
|
return permission.prepareUpdate(
|
||||||
protectedFunction(p => {
|
protectedFunction((p: TPermissionModel) => {
|
||||||
Object.assign(p, newPermission);
|
Object.assign(p, newPermission);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Delete
|
batch.push(...permissionsToCreate, ...permissionsToUpdate);
|
||||||
if (remove && remove.length) {
|
|
||||||
permissionsToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
|
|
||||||
permissionsToDelete = permissionsToDelete.map(permission => permission.prepareDestroyPermanently());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const batch = [...permissionsToCreate, ...permissionsToUpdate, ...permissionsToDelete];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.action(async () => {
|
await db.write(async () => {
|
||||||
await db.batch(...batch);
|
await db.batch(...batch);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
@ -137,18 +147,19 @@ const updatePermissions = async ({ update = [], remove = [], allRecords }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getPermissions() {
|
export function getPermissions(): Promise<void> {
|
||||||
return new Promise(async resolve => {
|
return new Promise(async resolve => {
|
||||||
try {
|
try {
|
||||||
const serverVersion = reduxStore.getState().server.version;
|
const serverVersion: string | null = reduxStore.getState().server.version;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const permissionsCollection = db.get('permissions');
|
const permissionsCollection = db.get('permissions');
|
||||||
const allRecords = await permissionsCollection.query().fetch();
|
const allRecords = await permissionsCollection.query().fetch();
|
||||||
RocketChat.subscribe('stream-notify-logged', 'permissions-changed');
|
RocketChat.subscribe('stream-notify-logged', 'permissions-changed');
|
||||||
// if server version is lower than 0.73.0, fetches from old api
|
// 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
|
// 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) {
|
if (!result.success) {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
@ -157,25 +168,25 @@ export function getPermissions() {
|
||||||
setPermissions();
|
setPermissions();
|
||||||
}
|
}
|
||||||
return resolve();
|
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) {
|
const params: { updatedSince?: string } = {};
|
||||||
return resolve();
|
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 (!result.success) {
|
||||||
if (changePermissions) {
|
|
||||||
setPermissions();
|
|
||||||
}
|
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changePermissions = await updatePermissions({ update: result.update, remove: result.remove, allRecords });
|
||||||
|
if (changePermissions) {
|
||||||
|
setPermissions();
|
||||||
|
}
|
||||||
|
return resolve();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
return resolve();
|
return resolve();
|
|
@ -1,6 +1,6 @@
|
||||||
import { setPermissions, updatePermission } from '../actions/permissions';
|
import { setPermissions, updatePermission } from '../actions/permissions';
|
||||||
import { mockedStore } from './mockedStore';
|
import { mockedStore } from './mockedStore';
|
||||||
import { initialState } from './permissions';
|
import { initialState, IPermissionsState } from './permissions';
|
||||||
|
|
||||||
describe('test permissions reducer', () => {
|
describe('test permissions reducer', () => {
|
||||||
it('should return initial state', () => {
|
it('should return initial state', () => {
|
||||||
|
@ -9,15 +9,15 @@ describe('test permissions reducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return modified store after setPermissions', () => {
|
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));
|
mockedStore.dispatch(setPermissions(permissions));
|
||||||
const state = mockedStore.getState().permissions;
|
const state = mockedStore.getState().permissions;
|
||||||
expect(state).toEqual(permissions);
|
expect(state).toEqual(permissions);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty store after remove user', () => {
|
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;
|
const state = mockedStore.getState().permissions;
|
||||||
expect(state.hasEditPermission).toEqual('disabled');
|
expect(state['add-team-channel']).toEqual(['owner']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import { PERMISSIONS } from '../actions/actionsTypes';
|
import { PERMISSIONS } from '../actions/actionsTypes';
|
||||||
import { TActionPermissions } from '../actions/permissions';
|
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) {
|
switch (action.type) {
|
||||||
case PERMISSIONS.SET:
|
case PERMISSIONS.SET:
|
||||||
return action.permissions;
|
return action.permissions;
|
||||||
|
|
|
@ -96,8 +96,8 @@ interface ICreateChannelViewProps extends IBaseScreen<ChatsStackParamList, 'Crea
|
||||||
roles: string[];
|
roles: string[];
|
||||||
};
|
};
|
||||||
teamId: string;
|
teamId: string;
|
||||||
createPublicChannelPermission: string[];
|
createPublicChannelPermission: string[] | undefined;
|
||||||
createPrivateChannelPermission: string[];
|
createPrivateChannelPermission: string[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISwitch extends SwitchProps {
|
interface ISwitch extends SwitchProps {
|
||||||
|
|
|
@ -87,8 +87,8 @@ interface ILivechatEditViewProps {
|
||||||
navigation: StackNavigationProp<ChatsStackParamList, 'LivechatEditView'>;
|
navigation: StackNavigationProp<ChatsStackParamList, 'LivechatEditView'>;
|
||||||
route: RouteProp<ChatsStackParamList, 'LivechatEditView'>;
|
route: RouteProp<ChatsStackParamList, 'LivechatEditView'>;
|
||||||
theme: string;
|
theme: string;
|
||||||
editOmnichannelContact: string[];
|
editOmnichannelContact: string[] | undefined;
|
||||||
editLivechatRoomCustomfields: string[];
|
editLivechatRoomCustomfields: string[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Title = ({ title, theme }: ITitle) =>
|
const Title = ({ title, theme }: ITitle) =>
|
||||||
|
|
|
@ -77,11 +77,11 @@ interface INewMessageViewProps extends IBaseScreen<any, 'NewMessageView'> {
|
||||||
maxUsers: number;
|
maxUsers: number;
|
||||||
isMasterDetail: boolean;
|
isMasterDetail: boolean;
|
||||||
serverVersion: string;
|
serverVersion: string;
|
||||||
createTeamPermission: string[];
|
createTeamPermission: string[] | undefined;
|
||||||
createDirectMessagePermission: string[];
|
createDirectMessagePermission: string[] | undefined;
|
||||||
createPublicChannelPermission: string[];
|
createPublicChannelPermission: string[] | undefined;
|
||||||
createPrivateChannelPermission: string[];
|
createPrivateChannelPermission: string[] | undefined;
|
||||||
createDiscussionPermission: string[];
|
createDiscussionPermission: string[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewMessageView extends React.Component<INewMessageViewProps, INewMessageViewState> {
|
class NewMessageView extends React.Component<INewMessageViewProps, INewMessageViewState> {
|
||||||
|
|
Loading…
Reference in New Issue