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:
Diego Mello 2022-02-17 10:06:31 -03:00 committed by GitHub
parent 86cc8a7d16
commit a58b27e4f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 70 deletions

View File

@ -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 }

View File

@ -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;

View File

@ -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';
@ -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;
@ -49,7 +51,7 @@ export interface IApplicationState {
inquiry: any;
enterpriseModules: IEnterpriseModules;
encryption: IEncryption;
permissions: any;
permissions: IPermissionsState;
roles: IRoles;
}
@ -67,4 +69,5 @@ export type TApplicationActions = TActionActiveUsers &
TActionsShare &
TActionServer &
TActionApp &
TActionPermissions &
TActionEnterpriseModules;

View File

@ -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',
@ -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;
@ -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;
@ -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();
}
@ -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();

View File

@ -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', () => {
@ -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']);
});
});

View File

@ -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;

View File

@ -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 {

View File

@ -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) =>

View File

@ -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> {