Skip to content

Commit

Permalink
Regression: Permissions missing on new Room Edit and Contact Edit form (
Browse files Browse the repository at this point in the history
#21315)

* Allow editing rooms in chat room

* Allow editing contact in chat room

* Fix default value error

* Move chats and contacts file out of omnichannel directory

* Show edit option for room info only if the user has permission

* Refactor + display room tags within edit only if user has permission

* Add permissions for editing omnichannel contact

* Re-add permission

* fix auto room-info panel routing issue

* Fix Permissions.

* Fix indentation.

Co-authored-by: Renato Becker <[email protected]>
Co-authored-by: Rafael Ferreira <[email protected]>
  • Loading branch information
3 people authored Apr 1, 2021
1 parent 9066ba8 commit f06fd76
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 130 deletions.
1 change: 1 addition & 0 deletions app/authorization/server/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Meteor.startup(function() {
{ _id: 'create-invite-links', roles: ['admin', 'owner', 'moderator'] },
{ _id: 'view-l-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] },
{ _id: 'view-livechat-manager', roles: ['livechat-manager', 'admin'] },
{ _id: 'edit-omnichannel-contact', roles: ['livechat-manager', 'admin', 'livechat-agent'] },
{ _id: 'view-livechat-rooms', roles: ['livechat-manager', 'admin'] },
{ _id: 'close-livechat-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] },
{ _id: 'close-others-livechat-room', roles: ['livechat-manager', 'admin'] },
Expand Down
2 changes: 1 addition & 1 deletion app/livechat/client/tabBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ addAction('room-info', {
id: 'room-info',
title: 'Room_Info',
icon: 'info-circled',
template: lazy(() => import('../../../client/omnichannel/directory/chats/contextualBar')),
template: lazy(() => import('../../../client/omnichannel/chats/contextualBar')),
order: 0,
});

Expand Down
2 changes: 1 addition & 1 deletion app/ui/client/views/app/room.js
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ Meteor.startup(() => {

let room = Rooms.findOne({ _id: rid }, { fields: { t: 1 } });

if (room?.t === 'l' && !FlowRouter.getParam('tab')) {
if (room?.t === 'l') {
room = Tracker.nonreactive(() => Rooms.findOne({ _id: rid }));
roomTypes.getConfig(room.t).openCustomProfileTab(this, room, room.v.username);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { Table, Tag, Box } from '@rocket.chat/fuselage';
import moment from 'moment';
import { Meteor } from 'meteor/meteor';

import { useTranslation } from '../../../contexts/TranslationContext';
import { useEndpointData } from '../../../hooks/useEndpointData';
import GenericTable from '../../../components/GenericTable';
import FilterByText from '../../../components/FilterByText';
import { usePermission } from '../../../contexts/AuthorizationContext';
import NotAuthorizedPage from '../../../components/NotAuthorizedPage';
import { useRoute } from '../../../contexts/RouterContext';
import { useTranslation } from '../../contexts/TranslationContext';
import { useEndpointData } from '../../hooks/useEndpointData';
import GenericTable from '../../components/GenericTable';
import FilterByText from '../../components/FilterByText';
import { usePermission } from '../../contexts/AuthorizationContext';
import NotAuthorizedPage from '../../components/NotAuthorizedPage';
import { useRoute } from '../../contexts/RouterContext';


const useQuery = ({ text, itemsPerPage, current }, [column, direction], userIdLoggedIn) => useMemo(() => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import { css } from '@rocket.chat/css-in-js';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import UAParser from 'ua-parser-js';

import VerticalBar from '../../../../components/VerticalBar';
import UserCard from '../../../../components/UserCard';
import { FormSkeleton } from '../../Skeleton';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import { useTranslation } from '../../../../contexts/TranslationContext';
import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime';
import { useFormatDuration } from '../../../../hooks/useFormatDuration';
import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
import UserAvatar from '../../../../components/avatar/UserAvatar';
import { UserStatus } from '../../../../components/UserStatus';
import { roomTypes } from '../../../../../app/utils/client';
import { useRoute } from '../../../../contexts/RouterContext';
import { hasPermission } from '../../../../../app/authorization';

import VerticalBar from '../../../components/VerticalBar';
import UserCard from '../../../components/UserCard';
import { FormSkeleton } from '../../directory/Skeleton';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext';
import { useTranslation } from '../../../contexts/TranslationContext';
import { useFormatDateAndTime } from '../../../hooks/useFormatDateAndTime';
import { useFormatDuration } from '../../../hooks/useFormatDuration';
import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import UserAvatar from '../../../components/avatar/UserAvatar';
import { UserStatus } from '../../../components/UserStatus';
import { roomTypes } from '../../../../app/utils/client';
import { useRoute } from '../../../contexts/RouterContext';
import { hasPermission } from '../../../../app/authorization';
import { useUserSubscription } from '../../../contexts/UserContext';

const wordBreak = css`
word-break: break-word;
Expand Down Expand Up @@ -164,8 +165,11 @@ export function ChatInfo({ id, route }) {
const { room: { ts, tags, closedAt, departmentId, v, servedBy, metrics, topic, waitingResponse, responseBy, priorityId, livechatData } } = data || { room: { v: { } } };
const routePath = useRoute(route || 'omnichannel-directory');
const canViewCustomFields = () => hasPermission('view-livechat-room-customfields');
const subscription = useUserSubscription(id);
const hasGlobalEditRoomPermission = hasPermission('save-others-livechat-room-info');
const visitorId = v?._id;

const dispatchToastMessage = useToastMessageDispatch();
useEffect(() => {
if (allCustomFields) {
const { customFields: customFieldsAPI } = allCustomFields;
Expand All @@ -179,15 +183,23 @@ export function ChatInfo({ id, route }) {
return false;
};

const onEditClick = useMutableCallback(() => routePath.push(
route ? {
context: 'edit',
id,
} : {
tab: 'chats',
context: 'edit',
id,
}));
const onEditClick = useMutableCallback(() => {
const hasEditAccess = !!subscription || hasGlobalEditRoomPermission;
if (!hasEditAccess) {
return dispatchToastMessage({ type: 'error', message: t('Not_authorized') });
}

routePath.push(
route ? {
tab: 'room-info',
context: 'edit',
id,
} : {
tab: 'chats',
context: 'edit',
id,
});
});


if (state === AsyncStatePhase.LOADING) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ import { Field, TextInput, ButtonGroup, Button, Box } from '@rocket.chat/fuselag
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSubscription } from 'use-subscription';

import { useTranslation } from '../../../../contexts/TranslationContext';
import VerticalBar from '../../../../components/VerticalBar';
import { useForm } from '../../../../hooks/useForm';
import { useToastMessageDispatch } from '../../../../contexts/ToastMessagesContext';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import { FormSkeleton } from '../../Skeleton';
import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
import { hasAtLeastOnePermission } from '../../../../../app/authorization';
import CustomFieldsForm from '../../../../components/CustomFieldsForm';
import { useMethod } from '../../../../contexts/ServerContext';
import { formsSubscription } from '../../../../views/omnichannel/additionalForms';

import { useTranslation } from '../../../contexts/TranslationContext';
import VerticalBar from '../../../components/VerticalBar';
import { useForm } from '../../../hooks/useForm';
import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { FormSkeleton } from '../../directory/Skeleton';
import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import { hasAtLeastOnePermission } from '../../../../app/authorization';
import CustomFieldsForm from '../../../components/CustomFieldsForm';
import { useMethod } from '../../../contexts/ServerContext';
import { formsSubscription } from '../../../views/omnichannel/additionalForms';

const initialValuesUser = {
name: '',
Expand Down Expand Up @@ -188,7 +187,7 @@ export function RoomEdit({ room, visitor, reload, close }) {
try {
saveRoom(userData, roomData);
dispatchToastMessage({ type: 'success', message: t('Saved') });
reload();
reload && reload();
close();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@ import React from 'react';
import { Icon, Box } from '@rocket.chat/fuselage';

import { ChatInfo } from './ChatInfo';
import VerticalBar from '../../../../components/VerticalBar';
import { useRoute } from '../../../../contexts/RouterContext';
import { useTranslation } from '../../../../contexts/TranslationContext';
import { RoomEditWithData } from './ChatRoomForm';
import VerticalBar from '../../../components/VerticalBar';
import { useRoute, useRouteParameter } from '../../../contexts/RouterContext';
import { useTranslation } from '../../../contexts/TranslationContext';

const PATH = 'live';

const ChatsContextualBar = ({ id }) => {
const t = useTranslation();

const context = useRouteParameter('context');

const directoryRoute = useRoute(PATH);

const closeContextualBar = () => {
directoryRoute.push({ id });
};

const handleRoomEditBarCloseButtonClick = () => {
directoryRoute.push({ id, tab: 'room-info' });
};

return <>
<VerticalBar.Header>
<Box flexShrink={1} flexGrow={1} withTruncatedText mi='x8'><Icon name='info-circled' size='x20' /> {t('Room_Info')}</Box>
<VerticalBar.Close onClick={closeContextualBar} />
</VerticalBar.Header>
<ChatInfo route={PATH} id={id} />
{context === 'edit' ? <RoomEditWithData id={id} close={handleRoomEditBarCloseButtonClick} /> : <ChatInfo route={PATH} id={id} />}
</>;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { useState, useMemo, useCallback, useEffect } from 'react';
import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { Table } from '@rocket.chat/fuselage';

import { useTranslation } from '../../../contexts/TranslationContext';
import { useEndpointData } from '../../../hooks/useEndpointData';
import GenericTable from '../../../components/GenericTable';
import FilterByText from '../../../components/FilterByText';
import { useRoute } from '../../../contexts/RouterContext';
import { useFormatDate } from '../../../hooks/useFormatDate';
import { usePermission } from '../../../contexts/AuthorizationContext';
import { NotAuthorizedPage } from '../../../components/NotAuthorizedPage';
import { useTranslation } from '../../contexts/TranslationContext';
import { useEndpointData } from '../../hooks/useEndpointData';
import GenericTable from '../../components/GenericTable';
import FilterByText from '../../components/FilterByText';
import { useRoute } from '../../contexts/RouterContext';
import { useFormatDate } from '../../hooks/useFormatDate';
import { usePermission } from '../../contexts/AuthorizationContext';
import { NotAuthorizedPage } from '../../components/NotAuthorizedPage';


const useQuery = ({ text, itemsPerPage, current }, [column, direction]) => useMemo(() => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import { Field, TextInput, ButtonGroup, Button, Box } from '@rocket.chat/fuselag
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSubscription } from 'use-subscription';

import { useTranslation } from '../../../../contexts/TranslationContext';
import VerticalBar from '../../../../components/VerticalBar';
import { useForm } from '../../../../hooks/useForm';
import { isEmail } from '../../../../../app/utils';
import { useComponentDidUpdate } from '../../../../hooks/useComponentDidUpdate';
import { useEndpointAction } from '../../../../hooks/useEndpointAction';
import { useToastMessageDispatch } from '../../../../contexts/ToastMessagesContext';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import { FormSkeleton } from '../../Skeleton';
import CustomFieldsForm from '../../../../components/CustomFieldsForm';
import { hasAtLeastOnePermission } from '../../../../../app/authorization';
import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
import { formsSubscription } from '../../../../views/omnichannel/additionalForms';
import { createToken } from '../../../../components/helpers';
import { useTranslation } from '../../../contexts/TranslationContext';
import VerticalBar from '../../../components/VerticalBar';
import { useForm } from '../../../hooks/useForm';
import { isEmail } from '../../../../app/utils';
import { useComponentDidUpdate } from '../../../hooks/useComponentDidUpdate';
import { useEndpointAction } from '../../../hooks/useEndpointAction';
import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { FormSkeleton } from '../../directory/Skeleton';
import CustomFieldsForm from '../../../components/CustomFieldsForm';
import { hasAtLeastOnePermission } from '../../../../app/authorization';
import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import { formsSubscription } from '../../../views/omnichannel/additionalForms';
import { createToken } from '../../../components/helpers';

const initialValues = {
token: '',
Expand All @@ -38,7 +38,7 @@ const getInitialValues = (data) => {
name: name ?? '',
email: visitorEmails ? visitorEmails[0].address : '',
phone: phone ? phone[0].phoneNumber : '',
livechatData: livechatData ?? '',
livechatData: livechatData ?? {},
username: contactManager?.username ?? '',
};
};
Expand Down Expand Up @@ -188,7 +188,7 @@ export function ContactNewEdit({ id, data, reload, close }) {
try {
await saveContact(payload);
dispatchToastMessage({ type: 'success', message: t('Saved') });
reload();
reload && reload();
close();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ import { css } from '@rocket.chat/css-in-js';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { FlowRouter } from 'meteor/kadira:flow-router';

import VerticalBar from '../../../../components/VerticalBar';
import UserCard from '../../../../components/UserCard';
import { FormSkeleton } from '../../Skeleton';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import { useTranslation } from '../../../../contexts/TranslationContext';
import { useRoute } from '../../../../contexts/RouterContext';
import { hasPermission } from '../../../../../app/authorization';
import { useFormatDate } from '../../../../hooks/useFormatDate';
import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
import { ContactManagerInfo } from '../../../../../ee/client/omnichannel/ContactManager';
import UserAvatar from '../../../../components/avatar/UserAvatar';
import { UserStatus } from '../../../../components/UserStatus';
import VerticalBar from '../../../components/VerticalBar';
import UserCard from '../../../components/UserCard';
import { FormSkeleton } from '../../directory/Skeleton';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext';
import { useTranslation } from '../../../contexts/TranslationContext';
import { useRoute } from '../../../contexts/RouterContext';
import { hasPermission } from '../../../../app/authorization';
import { useFormatDate } from '../../../hooks/useFormatDate';
import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import { ContactManagerInfo } from '../../../../ee/client/omnichannel/ContactManager';
import UserAvatar from '../../../components/avatar/UserAvatar';
import { UserStatus } from '../../../components/UserStatus';


const wordBreak = css`
Expand All @@ -40,24 +41,35 @@ const CustomField = ({ id, value }) => {
};


export function ContactInfo({ id }) {
export function ContactInfo({ id, rid, route }) {
const t = useTranslation();
const directoryRoute = useRoute('omnichannel-directory');
const routePath = useRoute(route || 'omnichannel-directory');

const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('livechat/custom-fields');

const [customFields, setCustomFields] = useState([]);

const formatDate = useFormatDate();

const dispatchToastMessage = useToastMessageDispatch();

const canViewCustomFields = () => hasPermission('view-livechat-room-customfields');

const onEditButtonClick = useMutableCallback(() => directoryRoute.push({
tab: 'contacts',
context: 'edit',
id,
}));
const onEditButtonClick = useMutableCallback(() => {
if (!hasPermission('edit-omnichannel-contact')) {
return dispatchToastMessage({ type: 'error', message: t('Not_authorized') });
}

routePath.push(route ? {
tab: 'contact-profile',
context: 'edit',
id: rid,
} : {
tab: 'contacts',
context: 'edit',
id,
});
});

useEffect(() => {
if (allCustomFields) {
Expand Down
40 changes: 40 additions & 0 deletions client/omnichannel/contacts/contextualBar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { Icon, Box } from '@rocket.chat/fuselage';

import VerticalBar from '../../../components/VerticalBar';
import { useRoute, useRouteParameter } from '../../../contexts/RouterContext';
import { useTranslation } from '../../../contexts/TranslationContext';
import { useRoom } from '../../../views/room/providers/RoomProvider';
import { ContactInfo } from './ContactInfo';
import { ContactEditWithData } from './ContactForm';

const PATH = 'live';
const ContactsContextualBar = ({ id }) => {
const t = useTranslation();

const directoryRoute = useRoute(PATH);

const context = useRouteParameter('context');

const closeContextualBar = () => {
directoryRoute.push({ id });
};

const handleContactEditBarCloseButtonClick = () => {
directoryRoute.push({ id, tab: 'contact-profile' });
};

const room = useRoom();

const { v: { _id } } = room;

return <>
<VerticalBar.Header>
<Box flexShrink={1} flexGrow={1} withTruncatedText mi='x8'><Icon name='user' size='x20' /> {t('Contact_Info')}</Box>
<VerticalBar.Close onClick={closeContextualBar} />
</VerticalBar.Header>
{context === 'edit' ? <ContactEditWithData id={_id} close={handleContactEditBarCloseButtonClick} /> : <ContactInfo id={_id} rid={id} route={PATH} />}
</>;
};

export default ({ rid }) => <ContactsContextualBar id={rid} />;
Loading

0 comments on commit f06fd76

Please sign in to comment.