feat: refactoring casl permission checks for recursive nested operations (#778)
* feat: nested casl abilities * fix: remove unused packages * Fixes * Fix createMany broken * Fix lint * Fix lint * Fix lint * Fix lint * Fixes * Fix CommentThread * Fix bugs * Fix lint * Fix bugs * Fixed auto routing * Fixed app path --------- Co-authored-by: Charles Bochet <charles@twenty.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
import { Button } from '@/ui/button/components/Button';
|
import { Button, ButtonVariant } from '@/ui/button/components/Button';
|
||||||
import { ButtonGroup } from '@/ui/button/components/ButtonGroup';
|
import { ButtonGroup } from '@/ui/button/components/ButtonGroup';
|
||||||
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@/ui/icon/index';
|
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@/ui/icon/index';
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export function CommentThreadCreateButton({
|
|||||||
}: CommentThreadCreateButtonProps) {
|
}: CommentThreadCreateButtonProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<ButtonGroup variant="secondary">
|
<ButtonGroup variant={ButtonVariant.Secondary}>
|
||||||
<Button
|
<Button
|
||||||
icon={<IconNotes size={theme.icon.size.sm} />}
|
icon={<IconNotes size={theme.icon.size.sm} />}
|
||||||
title="Note"
|
title="Note"
|
||||||
|
|||||||
190
front/src/modules/activities/components/CommentThreadEditor.tsx
Normal file
190
front/src/modules/activities/components/CommentThreadEditor.tsx
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { CommentThreadBodyEditor } from '@/activities/components/CommentThreadBodyEditor';
|
||||||
|
import { CommentThreadComments } from '@/activities/components/CommentThreadComments';
|
||||||
|
import { CommentThreadRelationPicker } from '@/activities/components/CommentThreadRelationPicker';
|
||||||
|
import { CommentThreadTypeDropdown } from '@/activities/components/CommentThreadTypeDropdown';
|
||||||
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/activities/queries';
|
||||||
|
import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox';
|
||||||
|
import { PropertyBoxItem } from '@/ui/editable-field/property-box/components/PropertyBoxItem';
|
||||||
|
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||||
|
import { IconArrowUpRight } from '@/ui/icon/index';
|
||||||
|
import {
|
||||||
|
CommentThread,
|
||||||
|
CommentThreadTarget,
|
||||||
|
useUpdateCommentThreadMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
import { debounce } from '~/utils/debounce';
|
||||||
|
|
||||||
|
import { CommentThreadActionBar } from '../right-drawer/components/CommentThreadActionBar';
|
||||||
|
import { CommentForDrawer } from '../types/CommentForDrawer';
|
||||||
|
|
||||||
|
import '@blocknote/core/style.css';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow-y: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledUpperPartContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
|
justify-content: flex-start;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTopContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border-bottom: ${({ theme }) =>
|
||||||
|
useIsMobile() ? 'none' : `1px solid ${theme.border.color.medium}`};
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 24px 24px 24px 48px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledEditableTitleInput = styled.input`
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xl};
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||||
|
outline: none;
|
||||||
|
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
||||||
|
&::placeholder {
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTopActionsContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
commentThread: Pick<CommentThread, 'id' | 'title' | 'body' | 'type'> & {
|
||||||
|
comments?: Array<CommentForDrawer> | null;
|
||||||
|
} & {
|
||||||
|
commentThreadTargets?: Array<
|
||||||
|
Pick<CommentThreadTarget, 'id' | 'commentableId' | 'commentableType'>
|
||||||
|
> | null;
|
||||||
|
};
|
||||||
|
showComment?: boolean;
|
||||||
|
autoFillTitle?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CommentThreadEditor({
|
||||||
|
commentThread,
|
||||||
|
showComment = true,
|
||||||
|
autoFillTitle = false,
|
||||||
|
}: OwnProps) {
|
||||||
|
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
|
||||||
|
const [title, setTitle] = useState<string | null>(commentThread.title ?? '');
|
||||||
|
|
||||||
|
const [updateCommentThreadMutation] = useUpdateCommentThreadMutation();
|
||||||
|
|
||||||
|
const updateTitle = useCallback(
|
||||||
|
(newTitle: string) => {
|
||||||
|
updateCommentThreadMutation({
|
||||||
|
variables: {
|
||||||
|
id: commentThread.id,
|
||||||
|
title: newTitle ?? '',
|
||||||
|
},
|
||||||
|
refetchQueries: [
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[commentThread, updateCommentThreadMutation],
|
||||||
|
);
|
||||||
|
const debouncedUpdateTitle = debounce(updateTitle, 200);
|
||||||
|
|
||||||
|
function updateTitleFromBody(body: string) {
|
||||||
|
const parsedTitle = JSON.parse(body)[0]?.content[0]?.text;
|
||||||
|
if (!hasUserManuallySetTitle && autoFillTitle) {
|
||||||
|
setTitle(parsedTitle);
|
||||||
|
debouncedUpdateTitle(parsedTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commentThread) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainer>
|
||||||
|
<StyledUpperPartContainer>
|
||||||
|
<StyledTopContainer>
|
||||||
|
<StyledTopActionsContainer>
|
||||||
|
<CommentThreadTypeDropdown commentThread={commentThread} />
|
||||||
|
<CommentThreadActionBar commentThreadId={commentThread?.id ?? ''} />
|
||||||
|
</StyledTopActionsContainer>
|
||||||
|
<StyledEditableTitleInput
|
||||||
|
autoComplete="off"
|
||||||
|
autoFocus
|
||||||
|
placeholder={`${commentThread.type} title (optional)`}
|
||||||
|
onChange={(event) => {
|
||||||
|
setHasUserManuallySetTitle(true);
|
||||||
|
setTitle(event.target.value);
|
||||||
|
debouncedUpdateTitle(event.target.value);
|
||||||
|
}}
|
||||||
|
value={title ?? ''}
|
||||||
|
/>
|
||||||
|
<PropertyBox>
|
||||||
|
<PropertyBoxItem
|
||||||
|
icon={<IconArrowUpRight />}
|
||||||
|
value={
|
||||||
|
<CommentThreadRelationPicker
|
||||||
|
commentThread={{
|
||||||
|
id: commentThread.id,
|
||||||
|
commentThreadTargets:
|
||||||
|
commentThread.commentThreadTargets ?? [],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Relations"
|
||||||
|
/>
|
||||||
|
</PropertyBox>
|
||||||
|
</StyledTopContainer>
|
||||||
|
<CommentThreadBodyEditor
|
||||||
|
commentThread={commentThread}
|
||||||
|
onChange={updateTitleFromBody}
|
||||||
|
/>
|
||||||
|
</StyledUpperPartContainer>
|
||||||
|
{showComment && (
|
||||||
|
<CommentThreadComments
|
||||||
|
commentThread={{
|
||||||
|
id: commentThread.id,
|
||||||
|
comments: commentThread.comments ?? [],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,88 +1,8 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import { CommentThreadEditor } from '@/activities/components/CommentThreadEditor';
|
||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { useGetCommentThreadQuery } from '~/generated/graphql';
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { CommentThreadBodyEditor } from '@/activities/components/CommentThreadBodyEditor';
|
|
||||||
import { CommentThreadComments } from '@/activities/components/CommentThreadComments';
|
|
||||||
import { CommentThreadRelationPicker } from '@/activities/components/CommentThreadRelationPicker';
|
|
||||||
import { CommentThreadTypeDropdown } from '@/activities/components/CommentThreadTypeDropdown';
|
|
||||||
import { GET_COMMENT_THREAD } from '@/activities/queries';
|
|
||||||
import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox';
|
|
||||||
import { PropertyBoxItem } from '@/ui/editable-field/property-box/components/PropertyBoxItem';
|
|
||||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
|
||||||
import { IconArrowUpRight } from '@/ui/icon/index';
|
|
||||||
import {
|
|
||||||
useGetCommentThreadQuery,
|
|
||||||
useUpdateCommentThreadMutation,
|
|
||||||
} from '~/generated/graphql';
|
|
||||||
import { debounce } from '~/utils/debounce';
|
|
||||||
|
|
||||||
import { CommentThreadActionBar } from './CommentThreadActionBar';
|
|
||||||
|
|
||||||
import '@blocknote/core/style.css';
|
import '@blocknote/core/style.css';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
overflow-y: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledUpperPartContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
gap: ${({ theme }) => theme.spacing(4)};
|
|
||||||
justify-content: flex-start;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledTopContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
align-self: stretch;
|
|
||||||
background: ${({ theme }) => theme.background.secondary};
|
|
||||||
border-bottom: ${({ theme }) =>
|
|
||||||
useIsMobile() ? 'none' : `1px solid ${theme.border.color.medium}`};
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 24px;
|
|
||||||
padding: 24px 24px 24px 48px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledEditableTitleInput = styled.input`
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
|
||||||
display: flex;
|
|
||||||
flex: 1 0 0;
|
|
||||||
|
|
||||||
flex-direction: column;
|
|
||||||
font-family: Inter;
|
|
||||||
font-size: ${({ theme }) => theme.font.size.xl};
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
|
||||||
outline: none;
|
|
||||||
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
|
||||||
&::placeholder {
|
|
||||||
color: ${({ theme }) => theme.font.color.light};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledTopActionsContainer = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
commentThreadId: string;
|
commentThreadId: string;
|
||||||
showComment?: boolean;
|
showComment?: boolean;
|
||||||
@ -101,103 +21,14 @@ export function CommentThread({
|
|||||||
skip: !commentThreadId,
|
skip: !commentThreadId,
|
||||||
});
|
});
|
||||||
const commentThread = data?.findManyCommentThreads[0];
|
const commentThread = data?.findManyCommentThreads[0];
|
||||||
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
|
||||||
useState<boolean>(false);
|
|
||||||
|
|
||||||
const [title, setTitle] = useState<string | null>(null);
|
return commentThread ? (
|
||||||
|
<CommentThreadEditor
|
||||||
useEffect(() => {
|
commentThread={commentThread}
|
||||||
if (!hasUserManuallySetTitle) {
|
showComment={showComment}
|
||||||
setTitle(commentThread?.title ?? '');
|
autoFillTitle={autoFillTitle}
|
||||||
}
|
/>
|
||||||
}, [setTitle, commentThread?.title, hasUserManuallySetTitle]);
|
) : (
|
||||||
|
<></>
|
||||||
const [updateCommentThreadMutation] = useUpdateCommentThreadMutation();
|
|
||||||
|
|
||||||
const debounceUpdateTitle = useMemo(() => {
|
|
||||||
function updateTitle(title: string) {
|
|
||||||
if (commentThread) {
|
|
||||||
updateCommentThreadMutation({
|
|
||||||
variables: {
|
|
||||||
id: commentThreadId,
|
|
||||||
title: title ?? '',
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_COMMENT_THREAD) ?? ''],
|
|
||||||
optimisticResponse: {
|
|
||||||
__typename: 'Mutation',
|
|
||||||
updateOneCommentThread: {
|
|
||||||
__typename: 'CommentThread',
|
|
||||||
id: commentThreadId,
|
|
||||||
title: title,
|
|
||||||
type: commentThread.type,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return debounce(updateTitle, 200);
|
|
||||||
}, [commentThreadId, updateCommentThreadMutation, commentThread]);
|
|
||||||
|
|
||||||
function updateTitleFromBody(body: string) {
|
|
||||||
const parsedTitle = JSON.parse(body)[0]?.content[0]?.text;
|
|
||||||
if (!hasUserManuallySetTitle && autoFillTitle) {
|
|
||||||
setTitle(parsedTitle);
|
|
||||||
debounceUpdateTitle(parsedTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!commentThread) {
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer>
|
|
||||||
<StyledUpperPartContainer>
|
|
||||||
<StyledTopContainer>
|
|
||||||
<StyledTopActionsContainer>
|
|
||||||
<CommentThreadTypeDropdown commentThread={commentThread} />
|
|
||||||
<CommentThreadActionBar commentThreadId={commentThread?.id ?? ''} />
|
|
||||||
</StyledTopActionsContainer>
|
|
||||||
<StyledEditableTitleInput
|
|
||||||
autoComplete="off"
|
|
||||||
autoFocus
|
|
||||||
placeholder={`${commentThread.type} title (optional)`}
|
|
||||||
onChange={(event) => {
|
|
||||||
setHasUserManuallySetTitle(true);
|
|
||||||
setTitle(event.target.value);
|
|
||||||
debounceUpdateTitle(event.target.value);
|
|
||||||
}}
|
|
||||||
value={title ?? ''}
|
|
||||||
/>
|
|
||||||
<PropertyBox>
|
|
||||||
<PropertyBoxItem
|
|
||||||
icon={<IconArrowUpRight />}
|
|
||||||
value={
|
|
||||||
<CommentThreadRelationPicker
|
|
||||||
commentThread={{
|
|
||||||
id: commentThread.id,
|
|
||||||
commentThreadTargets:
|
|
||||||
commentThread.commentThreadTargets ?? [],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Relations"
|
|
||||||
/>
|
|
||||||
</PropertyBox>
|
|
||||||
</StyledTopContainer>
|
|
||||||
<CommentThreadBodyEditor
|
|
||||||
commentThread={commentThread}
|
|
||||||
onChange={updateTitleFromBody}
|
|
||||||
/>
|
|
||||||
</StyledUpperPartContainer>
|
|
||||||
{showComment && (
|
|
||||||
<CommentThreadComments
|
|
||||||
commentThread={{
|
|
||||||
id: commentThread.id,
|
|
||||||
comments: commentThread.comments ?? [],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useRecoilState } from 'recoil';
|
|||||||
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/activities/queries';
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/activities/queries';
|
||||||
import { GET_COMPANIES } from '@/companies/queries';
|
import { GET_COMPANIES } from '@/companies/queries';
|
||||||
import { GET_PEOPLE } from '@/people/queries';
|
import { GET_PEOPLE } from '@/people/queries';
|
||||||
import { Button } from '@/ui/button/components/Button';
|
import { Button, ButtonVariant } from '@/ui/button/components/Button';
|
||||||
import { IconTrash } from '@/ui/icon';
|
import { IconTrash } from '@/ui/icon';
|
||||||
import { isRightDrawerOpenState } from '@/ui/right-drawer/states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '@/ui/right-drawer/states/isRightDrawerOpenState';
|
||||||
import { useDeleteCommentThreadMutation } from '~/generated/graphql';
|
import { useDeleteCommentThreadMutation } from '~/generated/graphql';
|
||||||
@ -44,7 +44,7 @@ export function CommentThreadActionBar({ commentThreadId }: OwnProps) {
|
|||||||
<IconTrash size={theme.icon.size.sm} stroke={theme.icon.stroke.md} />
|
<IconTrash size={theme.icon.size.sm} stroke={theme.icon.stroke.md} />
|
||||||
}
|
}
|
||||||
onClick={deleteCommentThread}
|
onClick={deleteCommentThread}
|
||||||
variant="tertiary"
|
variant={ButtonVariant.Tertiary}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { companyAddressFamilyState } from '@/companies/states/companyAddressFamilyState';
|
import { companyAddressFamilyState } from '@/companies/states/companyAddressFamilyState';
|
||||||
@ -15,28 +14,21 @@ export function EditableCompanyAddressCell() {
|
|||||||
companyAddressFamilyState(currentRowEntityId ?? ''),
|
companyAddressFamilyState(currentRowEntityId ?? ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
const [internalValue, setInternalValue] = useState(address ?? '');
|
|
||||||
useEffect(() => {
|
|
||||||
setInternalValue(address ?? '');
|
|
||||||
}, [address]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableCellText
|
<EditableCellText
|
||||||
value={internalValue}
|
value={address || ''}
|
||||||
onChange={setInternalValue}
|
onSubmit={(newAddress) =>
|
||||||
onSubmit={() =>
|
|
||||||
updateCompany({
|
updateCompany({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
id: currentRowEntityId,
|
id: currentRowEntityId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
address: internalValue,
|
address: newAddress,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onCancel={() => setInternalValue(address ?? '')}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { companyEmployeesFamilyState } from '@/companies/states/companyEmployeesFamilyState';
|
import { companyEmployeesFamilyState } from '@/companies/states/companyEmployeesFamilyState';
|
||||||
@ -15,30 +14,22 @@ export function EditableCompanyEmployeesCell() {
|
|||||||
companyEmployeesFamilyState(currentRowEntityId ?? ''),
|
companyEmployeesFamilyState(currentRowEntityId ?? ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
const [internalValue, setInternalValue] = useState(employees ?? '');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setInternalValue(employees ?? '');
|
|
||||||
}, [employees]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// TODO: Create an EditableCellNumber component
|
// TODO: Create an EditableCellNumber component
|
||||||
<EditableCellText
|
<EditableCellText
|
||||||
value={internalValue}
|
value={employees || ''}
|
||||||
onChange={setInternalValue}
|
onSubmit={(newValue) =>
|
||||||
onSubmit={() =>
|
|
||||||
updateCompany({
|
updateCompany({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
id: currentRowEntityId,
|
id: currentRowEntityId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
employees: parseInt(internalValue),
|
employees: parseInt(newValue),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onCancel={() => setInternalValue(employees ?? '')}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
||||||
@ -15,28 +14,22 @@ export function EditableCompanyLinkedinUrlCell() {
|
|||||||
const linkedinUrl = useRecoilValue(
|
const linkedinUrl = useRecoilValue(
|
||||||
companyLinkedinUrlFamilyState(currentRowEntityId ?? ''),
|
companyLinkedinUrlFamilyState(currentRowEntityId ?? ''),
|
||||||
);
|
);
|
||||||
const [internalValue, setInternalValue] = useState(linkedinUrl ?? '');
|
|
||||||
useEffect(() => {
|
|
||||||
setInternalValue(linkedinUrl ?? '');
|
|
||||||
}, [linkedinUrl]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableCellURL
|
<EditableCellURL
|
||||||
url={internalValue}
|
url={linkedinUrl || ''}
|
||||||
onChange={setInternalValue}
|
onSubmit={(newUrl) =>
|
||||||
onSubmit={() =>
|
|
||||||
updateCompany({
|
updateCompany({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
id: currentRowEntityId,
|
id: currentRowEntityId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
linkedinUrl: internalValue,
|
linkedinUrl: newUrl,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onCancel={() => setInternalValue(linkedinUrl ?? '')}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { peopleEmailFamilyState } from '@/people/states/peopleEmailFamilyState';
|
import { peopleEmailFamilyState } from '@/people/states/peopleEmailFamilyState';
|
||||||
@ -15,29 +14,21 @@ export function EditablePeopleEmailCell() {
|
|||||||
peopleEmailFamilyState(currentRowEntityId ?? ''),
|
peopleEmailFamilyState(currentRowEntityId ?? ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
const [internalValue, setInternalValue] = useState(email ?? '');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setInternalValue(email ?? '');
|
|
||||||
}, [email]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableCellText
|
<EditableCellText
|
||||||
value={internalValue}
|
value={email || ''}
|
||||||
onChange={setInternalValue}
|
onSubmit={(newEmail: string) =>
|
||||||
onSubmit={() =>
|
|
||||||
updatePerson({
|
updatePerson({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
id: currentRowEntityId,
|
id: currentRowEntityId,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
email: internalValue,
|
email: newEmail,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onCancel={() => setInternalValue(email ?? '')}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
export enum AppPath {
|
export enum AppPath {
|
||||||
// Not logged-in
|
// Not logged-in
|
||||||
Verify = 'verify',
|
Verify = '/verify',
|
||||||
SignIn = 'sign-in',
|
SignIn = '/sign-in',
|
||||||
SignUp = 'sign-up',
|
SignUp = '/sign-up',
|
||||||
Invite = 'invite/:workspaceInviteHash',
|
Invite = '/invite/:workspaceInviteHash',
|
||||||
|
|
||||||
// Onboarding
|
// Onboarding
|
||||||
CreateWorkspace = 'create/workspace',
|
CreateWorkspace = '/create/workspace',
|
||||||
CreateProfile = 'create/profile',
|
CreateProfile = '/create/profile',
|
||||||
|
|
||||||
// Onboarded
|
// Onboarded
|
||||||
Index = '',
|
Index = '/',
|
||||||
PeoplePage = '/people',
|
PeoplePage = '/people',
|
||||||
CompaniesPage = '/companies',
|
CompaniesPage = '/companies',
|
||||||
CompanyShowPage = '/companies/:companyId',
|
CompanyShowPage = '/companies/:companyId',
|
||||||
|
|||||||
@ -19,11 +19,11 @@ export function ButtonGroup({ children, variant, size }: ButtonGroupProps) {
|
|||||||
let position: ButtonPosition;
|
let position: ButtonPosition;
|
||||||
|
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
position = 'left';
|
position = ButtonPosition.Left;
|
||||||
} else if (index === children.length - 1) {
|
} else if (index === children.length - 1) {
|
||||||
position = 'right';
|
position = ButtonPosition.Right;
|
||||||
} else {
|
} else {
|
||||||
position = 'middle';
|
position = ButtonPosition.Middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const additionalProps: any = { position };
|
const additionalProps: any = { position };
|
||||||
|
|||||||
@ -48,6 +48,7 @@ export function InplaceInputTextEditMode({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInput
|
<StyledInput
|
||||||
|
autoComplete="off"
|
||||||
ref={wrapperRef}
|
ref={wrapperRef}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { Button } from '@/ui/button/components/Button';
|
import { Button, ButtonVariant } from '@/ui/button/components/Button';
|
||||||
import { IconFileUpload, IconTrash, IconUpload } from '@/ui/icon';
|
import { IconFileUpload, IconTrash, IconUpload } from '@/ui/icon';
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
@ -123,7 +123,7 @@ export function ImageInput({
|
|||||||
<Button
|
<Button
|
||||||
icon={<IconUpload size={theme.icon.size.sm} />}
|
icon={<IconUpload size={theme.icon.size.sm} />}
|
||||||
onClick={onUploadButtonClick}
|
onClick={onUploadButtonClick}
|
||||||
variant="secondary"
|
variant={ButtonVariant.Secondary}
|
||||||
title="Upload"
|
title="Upload"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -131,7 +131,7 @@ export function ImageInput({
|
|||||||
<Button
|
<Button
|
||||||
icon={<IconTrash size={theme.icon.size.sm} />}
|
icon={<IconTrash size={theme.icon.size.sm} />}
|
||||||
onClick={onRemove}
|
onClick={onRemove}
|
||||||
variant="secondary"
|
variant={ButtonVariant.Secondary}
|
||||||
title="Remove"
|
title="Remove"
|
||||||
disabled={!picture || disabled}
|
disabled={!picture || disabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -48,9 +48,9 @@ export function EditableCellDoubleTextEditMode({
|
|||||||
setSecondInternalValue(secondValue);
|
setSecondInternalValue(secondValue);
|
||||||
}, [firstValue, secondValue]);
|
}, [firstValue, secondValue]);
|
||||||
|
|
||||||
function handleOnChange(firstValue: string, secondValue: string): void {
|
function handleOnChange(newFirstValue: string, newSecondValue: string): void {
|
||||||
setFirstInternalValue(firstValue);
|
setFirstInternalValue(newFirstValue);
|
||||||
setSecondInternalValue(secondValue);
|
setSecondInternalValue(newSecondValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
|
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
|
||||||
@ -142,18 +142,18 @@ export function EditableCellDoubleTextEditMode({
|
|||||||
autoFocus
|
autoFocus
|
||||||
placeholder={firstValuePlaceholder}
|
placeholder={firstValuePlaceholder}
|
||||||
ref={firstValueInputRef}
|
ref={firstValueInputRef}
|
||||||
value={firstValue}
|
value={firstInternalValue}
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleOnChange(event.target.value, secondValue);
|
handleOnChange(event.target.value, secondInternalValue);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
placeholder={secondValuePlaceholder}
|
placeholder={secondValuePlaceholder}
|
||||||
ref={secondValueInputRef}
|
ref={secondValueInputRef}
|
||||||
value={secondValue}
|
value={secondInternalValue}
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleOnChange(firstValue, event.target.value);
|
handleOnChange(firstInternalValue, event.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
|
|||||||
@ -14,7 +14,6 @@ export function EditableCellPhone({ value, placeholder, onSubmit }: OwnProps) {
|
|||||||
<EditableCell
|
<EditableCell
|
||||||
editModeContent={
|
editModeContent={
|
||||||
<InplaceInputTextEditMode
|
<InplaceInputTextEditMode
|
||||||
autoComplete="off"
|
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ''}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -32,7 +32,6 @@ export function EditableCellText({
|
|||||||
autoFocus
|
autoFocus
|
||||||
value={value}
|
value={value}
|
||||||
onSubmit={(newText) => onSubmit?.(newText)}
|
onSubmit={(newText) => onSubmit?.(newText)}
|
||||||
autoComplete="off"
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
nonEditModeContent={
|
nonEditModeContent={
|
||||||
|
|||||||
@ -27,7 +27,6 @@ export function EditableCellURL({
|
|||||||
editModeContent={
|
editModeContent={
|
||||||
<InplaceInputTextEditMode
|
<InplaceInputTextEditMode
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
autoComplete="off"
|
|
||||||
autoFocus
|
autoFocus
|
||||||
value={url}
|
value={url}
|
||||||
onSubmit={(newURL) => onSubmit?.(newURL)}
|
onSubmit={(newURL) => onSubmit?.(newURL)}
|
||||||
|
|||||||
@ -56,7 +56,6 @@ export function EditableCellChip({
|
|||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ''}
|
||||||
autoFocus
|
autoFocus
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
autoComplete="off"
|
|
||||||
onSubmit={(newValue) => onSubmit?.(newValue)}
|
onSubmit={(newValue) => onSubmit?.(newValue)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { Button } from '@/ui/button/components/Button';
|
import { Button, ButtonVariant } from '@/ui/button/components/Button';
|
||||||
import { IconCopy, IconLink } from '@/ui/icon';
|
import { IconCopy, IconLink } from '@/ui/icon';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
||||||
@ -33,7 +33,7 @@ export function WorkspaceInviteLink({ inviteLink }: OwnProps) {
|
|||||||
</StyledLinkContainer>
|
</StyledLinkContainer>
|
||||||
<Button
|
<Button
|
||||||
icon={<IconLink size={theme.icon.size.md} />}
|
icon={<IconLink size={theme.icon.size.md} />}
|
||||||
variant="primary"
|
variant={ButtonVariant.Primary}
|
||||||
title="Copy link"
|
title="Copy link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
enqueueSnackBar('Link copied to clipboard', {
|
enqueueSnackBar('Link copied to clipboard', {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useAuth } from '@/auth/hooks/useAuth';
|
|||||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
|
|
||||||
import { AppPath } from '../../modules/types/AppPath';
|
import { AppPath } from '../../modules/types/AppPath';
|
||||||
|
import { isNonEmptyString } from '../../utils/isNonEmptyString';
|
||||||
|
|
||||||
export function Verify() {
|
export function Verify() {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
@ -20,8 +21,17 @@ export function Verify() {
|
|||||||
if (!loginToken) {
|
if (!loginToken) {
|
||||||
navigate(AppPath.SignIn);
|
navigate(AppPath.SignIn);
|
||||||
} else {
|
} else {
|
||||||
await verify(loginToken);
|
const verifyResponse = await verify(loginToken);
|
||||||
navigate(AppPath.CompaniesPage);
|
|
||||||
|
if (
|
||||||
|
isNonEmptyString(
|
||||||
|
verifyResponse.user.workspaceMember?.workspace.displayName,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
navigate(AppPath.Index);
|
||||||
|
} else {
|
||||||
|
navigate(AppPath.CreateWorkspace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,11 @@ import styled from '@emotion/styled';
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { Button } from '@/ui/button/components/Button';
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonSize,
|
||||||
|
ButtonVariant,
|
||||||
|
} from '@/ui/button/components/Button';
|
||||||
import { IconSettings, IconTrash } from '@/ui/icon';
|
import { IconSettings, IconTrash } from '@/ui/icon';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer';
|
||||||
import { MainSectionTitle } from '@/ui/title/components/MainSectionTitle';
|
import { MainSectionTitle } from '@/ui/title/components/MainSectionTitle';
|
||||||
@ -102,8 +106,8 @@ export function SettingsWorkspaceMembers() {
|
|||||||
<ButtonContainer>
|
<ButtonContainer>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleRemoveWorkspaceMember(member.user.id)}
|
onClick={() => handleRemoveWorkspaceMember(member.user.id)}
|
||||||
variant="tertiary"
|
variant={ButtonVariant.Tertiary}
|
||||||
size="small"
|
size={ButtonSize.Small}
|
||||||
icon={<IconTrash size={theme.icon.size.md} />}
|
icon={<IconTrash size={theme.icon.size.md} />}
|
||||||
/>
|
/>
|
||||||
</ButtonContainer>
|
</ButtonContainer>
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
"prebuild": "rimraf dist",
|
"prebuild": "rimraf dist",
|
||||||
"build": "nest build",
|
"build": "nest build",
|
||||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
"start": "set NODE_ENV=development&& nest start",
|
"start": "set NODE_ENV=development && nest start",
|
||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:debug": "nest start --debug --watch",
|
"start:debug": "nest start --debug --watch",
|
||||||
"start:prod": "node dist/main",
|
"start:prod": "node dist/main",
|
||||||
@ -32,7 +32,7 @@
|
|||||||
"@aws-sdk/client-s3": "^3.363.0",
|
"@aws-sdk/client-s3": "^3.363.0",
|
||||||
"@aws-sdk/credential-providers": "^3.363.0",
|
"@aws-sdk/credential-providers": "^3.363.0",
|
||||||
"@casl/ability": "^6.5.0",
|
"@casl/ability": "^6.5.0",
|
||||||
"@casl/prisma": "^1.4.0",
|
"@casl/prisma": "1.4.0",
|
||||||
"@nestjs/apollo": "^11.0.5",
|
"@nestjs/apollo": "^11.0.5",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.3.2",
|
"@nestjs/config": "^2.3.2",
|
||||||
@ -44,7 +44,7 @@
|
|||||||
"@nestjs/serve-static": "^3.0.0",
|
"@nestjs/serve-static": "^3.0.0",
|
||||||
"@nestjs/terminus": "^9.2.2",
|
"@nestjs/terminus": "^9.2.2",
|
||||||
"@paljs/plugins": "^5.3.3",
|
"@paljs/plugins": "^5.3.3",
|
||||||
"@prisma/client": "^4.13.0",
|
"@prisma/client": "4.13.0",
|
||||||
"@types/lodash.camelcase": "^4.3.7",
|
"@types/lodash.camelcase": "^4.3.7",
|
||||||
"@types/lodash.merge": "^4.6.7",
|
"@types/lodash.merge": "^4.6.7",
|
||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
@ -101,7 +101,7 @@
|
|||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"jest": "28.1.3",
|
"jest": "28.1.3",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"prisma": "^4.13.0",
|
"prisma": "4.13.0",
|
||||||
"prisma-nestjs-graphql": "^18.0.2",
|
"prisma-nestjs-graphql": "^18.0.2",
|
||||||
"prisma-query-log": "^3.2.0",
|
"prisma-query-log": "^3.2.0",
|
||||||
"source-map-support": "^0.5.20",
|
"source-map-support": "^0.5.20",
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
PipelineStage,
|
PipelineStage,
|
||||||
PipelineProgress,
|
PipelineProgress,
|
||||||
Attachment,
|
Attachment,
|
||||||
|
UserSettings,
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { AbilityAction } from './ability.action';
|
import { AbilityAction } from './ability.action';
|
||||||
@ -34,6 +35,7 @@ type SubjectsAbility = Subjects<{
|
|||||||
PipelineStage: PipelineStage;
|
PipelineStage: PipelineStage;
|
||||||
PipelineProgress: PipelineProgress;
|
PipelineProgress: PipelineProgress;
|
||||||
Attachment: Attachment;
|
Attachment: Attachment;
|
||||||
|
UserSettings: UserSettings;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type AppAbility = PureAbility<
|
export type AppAbility = PureAbility<
|
||||||
@ -58,8 +60,9 @@ export class AbilityFactory {
|
|||||||
cannot(AbilityAction.Delete, 'User');
|
cannot(AbilityAction.Delete, 'User');
|
||||||
|
|
||||||
// Workspace
|
// Workspace
|
||||||
can(AbilityAction.Read, 'Workspace', { id: workspace.id });
|
can(AbilityAction.Read, 'Workspace');
|
||||||
can(AbilityAction.Update, 'Workspace', { id: workspace.id });
|
can(AbilityAction.Update, 'Workspace');
|
||||||
|
can(AbilityAction.Delete, 'Workspace');
|
||||||
|
|
||||||
// Workspace Member
|
// Workspace Member
|
||||||
can(AbilityAction.Read, 'WorkspaceMember', { workspaceId: workspace.id });
|
can(AbilityAction.Read, 'WorkspaceMember', { workspaceId: workspace.id });
|
||||||
@ -101,6 +104,7 @@ export class AbilityFactory {
|
|||||||
|
|
||||||
// CommentThreadTarget
|
// CommentThreadTarget
|
||||||
can(AbilityAction.Read, 'CommentThreadTarget');
|
can(AbilityAction.Read, 'CommentThreadTarget');
|
||||||
|
can(AbilityAction.Create, 'CommentThreadTarget');
|
||||||
|
|
||||||
// Attachment
|
// Attachment
|
||||||
can(AbilityAction.Read, 'Attachment', { workspaceId: workspace.id });
|
can(AbilityAction.Read, 'Attachment', { workspaceId: workspace.id });
|
||||||
|
|||||||
207
server/src/ability/ability.util.ts
Normal file
207
server/src/ability/ability.util.ts
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
import { subject } from '@casl/ability';
|
||||||
|
|
||||||
|
import { camelCase } from 'src/utils/camel-case';
|
||||||
|
|
||||||
|
import { AppAbility } from './ability.factory';
|
||||||
|
import { AbilityAction } from './ability.action';
|
||||||
|
|
||||||
|
type OperationType =
|
||||||
|
| 'create'
|
||||||
|
| 'connectOrCreate'
|
||||||
|
| 'upsert'
|
||||||
|
| 'createMany'
|
||||||
|
| 'set'
|
||||||
|
| 'disconnect'
|
||||||
|
| 'delete'
|
||||||
|
| 'connect'
|
||||||
|
| 'update'
|
||||||
|
| 'updateMany'
|
||||||
|
| 'deleteMany';
|
||||||
|
|
||||||
|
// in most case unique identifier is the id, but it can be something else...
|
||||||
|
|
||||||
|
type OperationAbilityChecker = (
|
||||||
|
modelName: Prisma.ModelName,
|
||||||
|
ability: AppAbility,
|
||||||
|
prisma: PrismaClient,
|
||||||
|
data: any,
|
||||||
|
) => Promise<boolean>;
|
||||||
|
|
||||||
|
const createAbilityCheck: OperationAbilityChecker = async (
|
||||||
|
modelName,
|
||||||
|
ability,
|
||||||
|
prisma,
|
||||||
|
data,
|
||||||
|
) => {
|
||||||
|
// Handle all operations cases
|
||||||
|
const items = data?.data
|
||||||
|
? !Array.isArray(data.data)
|
||||||
|
? [data.data]
|
||||||
|
: data.data
|
||||||
|
: !Array.isArray(data)
|
||||||
|
? [data]
|
||||||
|
: data;
|
||||||
|
|
||||||
|
// Check if user try to create an element that is not allowed to create
|
||||||
|
for (const {} of items) {
|
||||||
|
if (!ability.can(AbilityAction.Create, modelName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const simpleAbilityCheck: OperationAbilityChecker = async (
|
||||||
|
modelName,
|
||||||
|
ability,
|
||||||
|
prisma,
|
||||||
|
data,
|
||||||
|
) => {
|
||||||
|
// Extract entity name from model name
|
||||||
|
const entity = camelCase(modelName);
|
||||||
|
// Handle all operations cases
|
||||||
|
const operations = !Array.isArray(data) ? [data] : data;
|
||||||
|
// Handle where case
|
||||||
|
const normalizedOperations = operations.map((op) =>
|
||||||
|
op.where ? op.where : op,
|
||||||
|
);
|
||||||
|
// Force entity type because of Prisma typing
|
||||||
|
const items = await prisma[entity as string].findMany({
|
||||||
|
where: {
|
||||||
|
OR: normalizedOperations,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if user try to connect an element that is not allowed to read
|
||||||
|
for (const item of items) {
|
||||||
|
// TODO: Replace user by workspaceMember and remove this check
|
||||||
|
if (
|
||||||
|
modelName === 'User' ||
|
||||||
|
modelName === 'UserSettings' ||
|
||||||
|
modelName === 'Workspace'
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ability.can(AbilityAction.Read, subject(modelName, item))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const operationAbilityCheckers: Record<OperationType, OperationAbilityChecker> =
|
||||||
|
{
|
||||||
|
create: createAbilityCheck,
|
||||||
|
createMany: createAbilityCheck,
|
||||||
|
upsert: simpleAbilityCheck,
|
||||||
|
update: simpleAbilityCheck,
|
||||||
|
updateMany: simpleAbilityCheck,
|
||||||
|
delete: simpleAbilityCheck,
|
||||||
|
deleteMany: simpleAbilityCheck,
|
||||||
|
connectOrCreate: simpleAbilityCheck,
|
||||||
|
connect: simpleAbilityCheck,
|
||||||
|
disconnect: simpleAbilityCheck,
|
||||||
|
set: simpleAbilityCheck,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check relation nested abilities
|
||||||
|
export async function relationAbilityChecker(
|
||||||
|
modelName: Prisma.ModelName,
|
||||||
|
ability: AppAbility,
|
||||||
|
prisma: PrismaClient,
|
||||||
|
args: any,
|
||||||
|
) {
|
||||||
|
// Extract models from Prisma
|
||||||
|
const models = Prisma.dmmf.datamodel.models;
|
||||||
|
// Find main model from options
|
||||||
|
const mainModel = models.find((item) => item.name === modelName);
|
||||||
|
|
||||||
|
if (!mainModel) {
|
||||||
|
throw new Error('Main model not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over fields
|
||||||
|
for (const field of mainModel.fields) {
|
||||||
|
// Check if field is a relation
|
||||||
|
if (field.relationName) {
|
||||||
|
// Check if field is in args
|
||||||
|
const operation = args.data?.[field.name] ?? args?.[field.name];
|
||||||
|
|
||||||
|
if (operation) {
|
||||||
|
// Extract operation name and value
|
||||||
|
const operationType = Object.keys(operation)[0] as OperationType;
|
||||||
|
const operationValue = operation[operationType];
|
||||||
|
|
||||||
|
// Get operation checker for the operation type
|
||||||
|
const operationChecker = operationAbilityCheckers[operationType];
|
||||||
|
|
||||||
|
if (!operationChecker) {
|
||||||
|
throw new Error('Operation not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if operation is allowed
|
||||||
|
const allowed = await operationChecker(
|
||||||
|
field.type as Prisma.ModelName,
|
||||||
|
ability,
|
||||||
|
prisma,
|
||||||
|
operationValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the 'create', 'connectOrCreate', 'upsert', 'update', and 'updateMany' operations,
|
||||||
|
// we should also check the nested operations.
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
'create',
|
||||||
|
'connectOrCreate',
|
||||||
|
'upsert',
|
||||||
|
'update',
|
||||||
|
'updateMany',
|
||||||
|
].includes(operationType)
|
||||||
|
) {
|
||||||
|
// Handle nested operations all cases
|
||||||
|
|
||||||
|
const operationValues = !Array.isArray(operationValue)
|
||||||
|
? [operationValue]
|
||||||
|
: operationValue;
|
||||||
|
|
||||||
|
// Loop over nested args
|
||||||
|
for (const nestedArgs of operationValues) {
|
||||||
|
const nestedCreateAllowed = await relationAbilityChecker(
|
||||||
|
field.type as Prisma.ModelName,
|
||||||
|
ability,
|
||||||
|
prisma,
|
||||||
|
nestedArgs.create ?? nestedArgs.data ?? nestedArgs,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nestedCreateAllowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nestedArgs.update) {
|
||||||
|
const nestedUpdateAllowed = await relationAbilityChecker(
|
||||||
|
field.type as Prisma.ModelName,
|
||||||
|
ability,
|
||||||
|
prisma,
|
||||||
|
nestedArgs.update,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nestedUpdateAllowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@ -42,7 +42,7 @@ export class CreateAttachmentAbilityHandler implements IAbilityHandler {
|
|||||||
const args = gqlContext.getArgs<AttachmentArgs>();
|
const args = gqlContext.getArgs<AttachmentArgs>();
|
||||||
assert(args.activityId, '', ForbiddenException);
|
assert(args.activityId, '', ForbiddenException);
|
||||||
|
|
||||||
const activity = await this.prismaService.commentThread.findUnique({
|
const activity = await this.prismaService.client.commentThread.findUnique({
|
||||||
where: { id: args.activityId },
|
where: { id: args.activityId },
|
||||||
include: { workspace: true },
|
include: { workspace: true },
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { CommentThreadTargetWhereInput } from 'src/core/@generated/comment-thread-target/comment-thread-target-where.input';
|
import { CommentThreadTargetWhereInput } from 'src/core/@generated/comment-thread-target/comment-thread-target-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class CommentThreadTargetArgs {
|
class CommentThreadTargetArgs {
|
||||||
where?: CommentThreadTargetWhereInput;
|
where?: CommentThreadTargetWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -39,7 +41,23 @@ export class ReadCommentThreadTargetAbilityHandler implements IAbilityHandler {
|
|||||||
export class CreateCommentThreadTargetAbilityHandler
|
export class CreateCommentThreadTargetAbilityHandler
|
||||||
implements IAbilityHandler
|
implements IAbilityHandler
|
||||||
{
|
{
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'CommentThreadTarget',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'CommentThreadTarget');
|
return ability.can(AbilityAction.Create, 'CommentThreadTarget');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,11 +72,22 @@ export class UpdateCommentThreadTargetAbilityHandler
|
|||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
||||||
const commentThreadTarget =
|
const commentThreadTarget =
|
||||||
await this.prismaService.commentThreadTarget.findFirst({
|
await this.prismaService.client.commentThreadTarget.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(commentThreadTarget, '', NotFoundException);
|
assert(commentThreadTarget, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'CommentThreadTarget',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('CommentThreadTarget', commentThreadTarget),
|
subject('CommentThreadTarget', commentThreadTarget),
|
||||||
@ -76,7 +105,7 @@ export class DeleteCommentThreadTargetAbilityHandler
|
|||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
||||||
const commentThreadTarget =
|
const commentThreadTarget =
|
||||||
await this.prismaService.commentThreadTarget.findFirst({
|
await this.prismaService.client.commentThreadTarget.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(commentThreadTarget, '', NotFoundException);
|
assert(commentThreadTarget, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { CommentThreadWhereInput } from 'src/core/@generated/comment-thread/comment-thread-where.input';
|
import { CommentThreadWhereInput } from 'src/core/@generated/comment-thread/comment-thread-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class CommentThreadArgs {
|
class CommentThreadArgs {
|
||||||
where?: CommentThreadWhereInput;
|
where?: CommentThreadWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadCommentThreadAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateCommentThreadAbilityHandler implements IAbilityHandler {
|
export class CreateCommentThreadAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'CommentThread',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'CommentThread');
|
return ability.can(AbilityAction.Create, 'CommentThread');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,23 @@ export class UpdateCommentThreadAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentThreadArgs>();
|
const args = gqlContext.getArgs<CommentThreadArgs>();
|
||||||
const commentThread = await this.prismaService.commentThread.findFirst({
|
const commentThread =
|
||||||
where: args.where,
|
await this.prismaService.client.commentThread.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(commentThread, '', NotFoundException);
|
assert(commentThread, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'CommentThread',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('CommentThread', commentThread),
|
subject('CommentThread', commentThread),
|
||||||
@ -66,9 +96,10 @@ export class DeleteCommentThreadAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentThreadArgs>();
|
const args = gqlContext.getArgs<CommentThreadArgs>();
|
||||||
const commentThread = await this.prismaService.commentThread.findFirst({
|
const commentThread =
|
||||||
where: args.where,
|
await this.prismaService.client.commentThread.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(commentThread, '', NotFoundException);
|
assert(commentThread, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { CommentWhereInput } from 'src/core/@generated/comment/comment-where.input';
|
import { CommentWhereInput } from 'src/core/@generated/comment/comment-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class CommentArgs {
|
class CommentArgs {
|
||||||
where?: CommentWhereInput;
|
where?: CommentWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadCommentAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateCommentAbilityHandler implements IAbilityHandler {
|
export class CreateCommentAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Comment',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'Comment');
|
return ability.can(AbilityAction.Create, 'Comment');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,22 @@ export class UpdateCommentAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentArgs>();
|
const args = gqlContext.getArgs<CommentArgs>();
|
||||||
const comment = await this.prismaService.comment.findFirst({
|
const comment = await this.prismaService.client.comment.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(comment, '', NotFoundException);
|
assert(comment, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Comment',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('Comment', comment));
|
return ability.can(AbilityAction.Update, subject('Comment', comment));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +92,7 @@ export class DeleteCommentAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CommentArgs>();
|
const args = gqlContext.getArgs<CommentArgs>();
|
||||||
const comment = await this.prismaService.comment.findFirst({
|
const comment = await this.prismaService.client.comment.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(comment, '', NotFoundException);
|
assert(comment, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { CompanyWhereInput } from 'src/core/@generated/company/company-where.input';
|
import { CompanyWhereInput } from 'src/core/@generated/company/company-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class CompanyArgs {
|
class CompanyArgs {
|
||||||
where?: CompanyWhereInput;
|
where?: CompanyWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadCompanyAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateCompanyAbilityHandler implements IAbilityHandler {
|
export class CreateCompanyAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Company',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'Company');
|
return ability.can(AbilityAction.Create, 'Company');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,12 +65,22 @@ export class UpdateCompanyAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CompanyArgs>();
|
const args = gqlContext.getArgs<CompanyArgs>();
|
||||||
const company = await this.prismaService.company.findFirst({
|
const company = await this.prismaService.client.company.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(company, '', NotFoundException);
|
assert(company, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Company',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('Company', company));
|
return ability.can(AbilityAction.Update, subject('Company', company));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +92,7 @@ export class DeleteCompanyAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<CompanyArgs>();
|
const args = gqlContext.getArgs<CompanyArgs>();
|
||||||
const company = await this.prismaService.company.findFirst({
|
const company = await this.prismaService.client.company.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(company, '', NotFoundException);
|
assert(company, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { PersonWhereInput } from 'src/core/@generated/person/person-where.input';
|
import { PersonWhereInput } from 'src/core/@generated/person/person-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class PersonArgs {
|
class PersonArgs {
|
||||||
where?: PersonWhereInput;
|
where?: PersonWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadPersonAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreatePersonAbilityHandler implements IAbilityHandler {
|
export class CreatePersonAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Person',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'Person');
|
return ability.can(AbilityAction.Create, 'Person');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,22 @@ export class UpdatePersonAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PersonArgs>();
|
const args = gqlContext.getArgs<PersonArgs>();
|
||||||
const person = await this.prismaService.person.findFirst({
|
const person = await this.prismaService.client.person.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(person, '', NotFoundException);
|
assert(person, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Person',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('Person', person));
|
return ability.can(AbilityAction.Update, subject('Person', person));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +92,7 @@ export class DeletePersonAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PersonArgs>();
|
const args = gqlContext.getArgs<PersonArgs>();
|
||||||
const person = await this.prismaService.person.findFirst({
|
const person = await this.prismaService.client.person.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(person, '', NotFoundException);
|
assert(person, '', NotFoundException);
|
||||||
|
|||||||
@ -12,11 +12,13 @@ import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interfac
|
|||||||
import { PrismaService } from 'src/database/prisma.service';
|
import { PrismaService } from 'src/database/prisma.service';
|
||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { assert } from 'src/utils/assert';
|
|
||||||
import { PipelineProgressWhereInput } from 'src/core/@generated/pipeline-progress/pipeline-progress-where.input';
|
import { PipelineProgressWhereInput } from 'src/core/@generated/pipeline-progress/pipeline-progress-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class PipelineProgressArgs {
|
class PipelineProgressArgs {
|
||||||
where?: PipelineProgressWhereInput;
|
where?: PipelineProgressWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadPipelineProgressAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreatePipelineProgressAbilityHandler implements IAbilityHandler {
|
export class CreatePipelineProgressAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'PipelineProgress',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'PipelineProgress');
|
return ability.can(AbilityAction.Create, 'PipelineProgress');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,11 +66,22 @@ export class UpdatePipelineProgressAbilityHandler implements IAbilityHandler {
|
|||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
||||||
const pipelineProgress =
|
const pipelineProgress =
|
||||||
await this.prismaService.pipelineProgress.findFirst({
|
await this.prismaService.client.pipelineProgress.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(pipelineProgress, '', NotFoundException);
|
assert(pipelineProgress, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'PipelineProgress',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('PipelineProgress', pipelineProgress),
|
subject('PipelineProgress', pipelineProgress),
|
||||||
@ -68,7 +97,7 @@ export class DeletePipelineProgressAbilityHandler implements IAbilityHandler {
|
|||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
||||||
const pipelineProgress =
|
const pipelineProgress =
|
||||||
await this.prismaService.pipelineProgress.findFirst({
|
await this.prismaService.client.pipelineProgress.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(pipelineProgress, '', NotFoundException);
|
assert(pipelineProgress, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { PipelineStageWhereInput } from 'src/core/@generated/pipeline-stage/pipeline-stage-where.input';
|
import { PipelineStageWhereInput } from 'src/core/@generated/pipeline-stage/pipeline-stage-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class PipelineStageArgs {
|
class PipelineStageArgs {
|
||||||
where?: PipelineStageWhereInput;
|
where?: PipelineStageWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadPipelineStageAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreatePipelineStageAbilityHandler implements IAbilityHandler {
|
export class CreatePipelineStageAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'PipelineStage',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'PipelineStage');
|
return ability.can(AbilityAction.Create, 'PipelineStage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,23 @@ export class UpdatePipelineStageAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineStageArgs>();
|
const args = gqlContext.getArgs<PipelineStageArgs>();
|
||||||
const pipelineStage = await this.prismaService.pipelineStage.findFirst({
|
const pipelineStage =
|
||||||
where: args.where,
|
await this.prismaService.client.pipelineStage.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(pipelineStage, '', NotFoundException);
|
assert(pipelineStage, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'PipelineStage',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('PipelineStage', pipelineStage),
|
subject('PipelineStage', pipelineStage),
|
||||||
@ -66,9 +96,10 @@ export class DeletePipelineStageAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineStageArgs>();
|
const args = gqlContext.getArgs<PipelineStageArgs>();
|
||||||
const pipelineStage = await this.prismaService.pipelineStage.findFirst({
|
const pipelineStage =
|
||||||
where: args.where,
|
await this.prismaService.client.pipelineStage.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(pipelineStage, '', NotFoundException);
|
assert(pipelineStage, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { PipelineWhereInput } from 'src/core/@generated/pipeline/pipeline-where.input';
|
import { PipelineWhereInput } from 'src/core/@generated/pipeline/pipeline-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class PipelineArgs {
|
class PipelineArgs {
|
||||||
where?: PipelineWhereInput;
|
where?: PipelineWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadPipelineAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreatePipelineAbilityHandler implements IAbilityHandler {
|
export class CreatePipelineAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Pipeline',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'Pipeline');
|
return ability.can(AbilityAction.Create, 'Pipeline');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,22 @@ export class UpdatePipelineAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineArgs>();
|
const args = gqlContext.getArgs<PipelineArgs>();
|
||||||
const pipeline = await this.prismaService.pipeline.findFirst({
|
const pipeline = await this.prismaService.client.pipeline.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(pipeline, '', NotFoundException);
|
assert(pipeline, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Pipeline',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('Pipeline', pipeline));
|
return ability.can(AbilityAction.Update, subject('Pipeline', pipeline));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +92,7 @@ export class DeletePipelineAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<PipelineArgs>();
|
const args = gqlContext.getArgs<PipelineArgs>();
|
||||||
const pipeline = await this.prismaService.pipeline.findFirst({
|
const pipeline = await this.prismaService.client.pipeline.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(pipeline, '', NotFoundException);
|
assert(pipeline, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { RefreshTokenWhereInput } from 'src/core/@generated/refresh-token/refresh-token-where.input';
|
import { RefreshTokenWhereInput } from 'src/core/@generated/refresh-token/refresh-token-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class RefreshTokenArgs {
|
class RefreshTokenArgs {
|
||||||
where?: RefreshTokenWhereInput;
|
where?: RefreshTokenWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadRefreshTokenAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateRefreshTokenAbilityHandler implements IAbilityHandler {
|
export class CreateRefreshTokenAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'RefreshToken',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'RefreshToken');
|
return ability.can(AbilityAction.Create, 'RefreshToken');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,24 @@ export class UpdateRefreshTokenAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
||||||
const refreshToken = await this.prismaService.refreshToken.findFirst({
|
const refreshToken = await this.prismaService.client.refreshToken.findFirst(
|
||||||
where: args.where,
|
{
|
||||||
});
|
where: args.where,
|
||||||
|
},
|
||||||
|
);
|
||||||
assert(refreshToken, '', NotFoundException);
|
assert(refreshToken, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'RefreshToken',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('RefreshToken', refreshToken),
|
subject('RefreshToken', refreshToken),
|
||||||
@ -66,9 +97,11 @@ export class DeleteRefreshTokenAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
||||||
const refreshToken = await this.prismaService.refreshToken.findFirst({
|
const refreshToken = await this.prismaService.client.refreshToken.findFirst(
|
||||||
where: args.where,
|
{
|
||||||
});
|
where: args.where,
|
||||||
|
},
|
||||||
|
);
|
||||||
assert(refreshToken, '', NotFoundException);
|
assert(refreshToken, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
|
|||||||
@ -12,11 +12,13 @@ import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interfac
|
|||||||
import { PrismaService } from 'src/database/prisma.service';
|
import { PrismaService } from 'src/database/prisma.service';
|
||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { assert } from 'src/utils/assert';
|
|
||||||
import { UserWhereInput } from 'src/core/@generated/user/user-where.input';
|
import { UserWhereInput } from 'src/core/@generated/user/user-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class UserArgs {
|
class UserArgs {
|
||||||
where?: UserWhereInput;
|
where?: UserWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadUserAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateUserAbilityHandler implements IAbilityHandler {
|
export class CreateUserAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'User',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'User');
|
return ability.can(AbilityAction.Create, 'User');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +65,22 @@ export class UpdateUserAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<UserArgs>();
|
const args = gqlContext.getArgs<UserArgs>();
|
||||||
const user = await this.prismaService.user.findFirst({
|
const user = await this.prismaService.client.user.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(user, '', NotFoundException);
|
assert(user, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'User',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('User', user));
|
return ability.can(AbilityAction.Update, subject('User', user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +92,7 @@ export class DeleteUserAbilityHandler implements IAbilityHandler {
|
|||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<UserArgs>();
|
const args = gqlContext.getArgs<UserArgs>();
|
||||||
const user = await this.prismaService.user.findFirst({
|
const user = await this.prismaService.client.user.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(user, '', NotFoundException);
|
assert(user, '', NotFoundException);
|
||||||
|
|||||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
|||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { WorkspaceMemberWhereInput } from 'src/core/@generated/workspace-member/workspace-member-where.input';
|
import { WorkspaceMemberWhereInput } from 'src/core/@generated/workspace-member/workspace-member-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
|
||||||
class WorksapceMemberArgs {
|
class WorkspaceMemberArgs {
|
||||||
where?: WorkspaceMemberWhereInput;
|
where?: WorkspaceMemberWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -35,7 +37,23 @@ export class ReadWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
export class CreateWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'WorkspaceMember',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'WorkspaceMember');
|
return ability.can(AbilityAction.Create, 'WorkspaceMember');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,12 +64,24 @@ export class UpdateWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<WorksapceMemberArgs>();
|
const args = gqlContext.getArgs<WorkspaceMemberArgs>();
|
||||||
const workspaceMember = await this.prismaService.workspaceMember.findFirst({
|
const workspaceMember =
|
||||||
where: args.where,
|
await this.prismaService.client.workspaceMember.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(workspaceMember, '', NotFoundException);
|
assert(workspaceMember, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'WorkspaceMember',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
AbilityAction.Update,
|
AbilityAction.Update,
|
||||||
subject('WorkspaceMember', workspaceMember),
|
subject('WorkspaceMember', workspaceMember),
|
||||||
@ -65,10 +95,11 @@ export class DeleteWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<WorksapceMemberArgs>();
|
const args = gqlContext.getArgs<WorkspaceMemberArgs>();
|
||||||
const workspaceMember = await this.prismaService.workspaceMember.findFirst({
|
const workspaceMember =
|
||||||
where: args.where,
|
await this.prismaService.client.workspaceMember.findFirst({
|
||||||
});
|
where: args.where,
|
||||||
|
});
|
||||||
assert(workspaceMember, '', NotFoundException);
|
assert(workspaceMember, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(
|
return ability.can(
|
||||||
|
|||||||
@ -1,24 +1,22 @@
|
|||||||
import {
|
import {
|
||||||
ExecutionContext,
|
ExecutionContext,
|
||||||
ForbiddenException,
|
|
||||||
Injectable,
|
Injectable,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||||
|
|
||||||
import { subject } from '@casl/ability';
|
|
||||||
|
|
||||||
import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interface';
|
import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interface';
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
import { PrismaService } from 'src/database/prisma.service';
|
||||||
import { AbilityAction } from 'src/ability/ability.action';
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
import { AppAbility } from 'src/ability/ability.factory';
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
import { WorkspaceWhereInput } from 'src/core/@generated/workspace/workspace-where.input';
|
import { WorkspaceWhereInput } from 'src/core/@generated/workspace/workspace-where.input';
|
||||||
|
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
import { getRequest } from 'src/utils/extract-request';
|
|
||||||
|
|
||||||
class WorksapceArgs {
|
class WorkspaceArgs {
|
||||||
where?: WorkspaceWhereInput;
|
where?: WorkspaceWhereInput;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -37,7 +35,23 @@ export class ReadWorkspaceAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateWorkspaceAbilityHandler implements IAbilityHandler {
|
export class CreateWorkspaceAbilityHandler implements IAbilityHandler {
|
||||||
handle(ability: AppAbility) {
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Workspace',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return ability.can(AbilityAction.Create, 'Workspace');
|
return ability.can(AbilityAction.Create, 'Workspace');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,15 +61,25 @@ export class UpdateWorkspaceAbilityHandler implements IAbilityHandler {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const request = getRequest(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
assert(request.user.workspace.id, '', ForbiddenException);
|
const args = gqlContext.getArgs<WorkspaceArgs>();
|
||||||
|
const workspace = await this.prismaService.client.workspace.findFirst({
|
||||||
const workspace = await this.prismaService.workspace.findUnique({
|
where: args.where,
|
||||||
where: { id: request.user.workspace.id },
|
|
||||||
});
|
});
|
||||||
assert(workspace, '', NotFoundException);
|
assert(workspace, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(AbilityAction.Update, subject('Workspace', workspace));
|
const allowed = await relationAbilityChecker(
|
||||||
|
'Workspace',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ability.can(AbilityAction.Update, 'Workspace');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,12 +89,12 @@ export class DeleteWorkspaceAbilityHandler implements IAbilityHandler {
|
|||||||
|
|
||||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
const args = gqlContext.getArgs<WorksapceArgs>();
|
const args = gqlContext.getArgs<WorkspaceArgs>();
|
||||||
const workspace = await this.prismaService.workspace.findFirst({
|
const workspace = await this.prismaService.client.workspace.findFirst({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
});
|
});
|
||||||
assert(workspace, '', NotFoundException);
|
assert(workspace, '', NotFoundException);
|
||||||
|
|
||||||
return ability.can(AbilityAction.Delete, subject('Workspace', workspace));
|
return ability.can(AbilityAction.Delete, 'Workspace');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,35 +9,35 @@ export class AttachmentService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.attachment.findFirst;
|
findFirst = this.prismaService.client.attachment.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.attachment.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.attachment.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.attachment.findUnique;
|
findUnique = this.prismaService.client.attachment.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.attachment.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.attachment.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.attachment.findMany;
|
findMany = this.prismaService.client.attachment.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.attachment.create;
|
create = this.prismaService.client.attachment.create;
|
||||||
createMany = this.prismaService.attachment.createMany;
|
createMany = this.prismaService.client.attachment.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.attachment.update;
|
update = this.prismaService.client.attachment.update;
|
||||||
upsert = this.prismaService.attachment.upsert;
|
upsert = this.prismaService.client.attachment.upsert;
|
||||||
updateMany = this.prismaService.attachment.updateMany;
|
updateMany = this.prismaService.client.attachment.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.attachment.delete;
|
delete = this.prismaService.client.attachment.delete;
|
||||||
deleteMany = this.prismaService.attachment.deleteMany;
|
deleteMany = this.prismaService.client.attachment.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.attachment.aggregate;
|
aggregate = this.prismaService.client.attachment.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.attachment.count;
|
count = this.prismaService.client.attachment.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.attachment.groupBy;
|
groupBy = this.prismaService.client.attachment.groupBy;
|
||||||
|
|
||||||
getFileTypeFromFileName(fileName: string): AttachmentType {
|
getFileTypeFromFileName(fileName: string): AttachmentType {
|
||||||
const extension = fileName.split('.').pop()?.toLowerCase();
|
const extension = fileName.split('.').pop()?.toLowerCase();
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export class TokenService {
|
|||||||
assert(expiresIn, '', InternalServerErrorException);
|
assert(expiresIn, '', InternalServerErrorException);
|
||||||
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
|
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
|
||||||
|
|
||||||
const user = await this.prismaService.user.findUnique({
|
const user = await this.prismaService.client.user.findUnique({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
include: {
|
include: {
|
||||||
workspaceMember: true,
|
workspaceMember: true,
|
||||||
@ -71,7 +71,7 @@ export class TokenService {
|
|||||||
sub: userId,
|
sub: userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshToken = await this.prismaService.refreshToken.create({
|
const refreshToken = await this.prismaService.client.refreshToken.create({
|
||||||
data: refreshTokenPayload,
|
data: refreshTokenPayload,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,13 +122,13 @@ export class TokenService {
|
|||||||
UnprocessableEntityException,
|
UnprocessableEntityException,
|
||||||
);
|
);
|
||||||
|
|
||||||
const token = await this.prismaService.refreshToken.findUnique({
|
const token = await this.prismaService.client.refreshToken.findUnique({
|
||||||
where: { id: jwtPayload.jti },
|
where: { id: jwtPayload.jti },
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(token, "This refresh token doesn't exist", NotFoundException);
|
assert(token, "This refresh token doesn't exist", NotFoundException);
|
||||||
|
|
||||||
const user = await this.prismaService.user.findUnique({
|
const user = await this.prismaService.client.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: jwtPayload.sub,
|
id: jwtPayload.sub,
|
||||||
},
|
},
|
||||||
@ -141,7 +141,7 @@ export class TokenService {
|
|||||||
|
|
||||||
if (token.isRevoked) {
|
if (token.isRevoked) {
|
||||||
// Revoke all user refresh tokens
|
// Revoke all user refresh tokens
|
||||||
await this.prismaService.refreshToken.updateMany({
|
await this.prismaService.client.refreshToken.updateMany({
|
||||||
where: {
|
where: {
|
||||||
id: {
|
id: {
|
||||||
in: user.refreshTokens.map(({ id }) => id),
|
in: user.refreshTokens.map(({ id }) => id),
|
||||||
@ -172,7 +172,7 @@ export class TokenService {
|
|||||||
} = await this.verifyRefreshToken(token);
|
} = await this.verifyRefreshToken(token);
|
||||||
|
|
||||||
// Revoke old refresh token
|
// Revoke old refresh token
|
||||||
await this.prismaService.refreshToken.update({
|
await this.prismaService.client.refreshToken.update({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: JwtPayload): Promise<PassportUser> {
|
async validate(payload: JwtPayload): Promise<PassportUser> {
|
||||||
const user = await this.prismaService.user.findUniqueOrThrow({
|
const user = await this.prismaService.client.user.findUniqueOrThrow({
|
||||||
where: { id: payload.sub },
|
where: { id: payload.sub },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -32,9 +32,10 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspace = await this.prismaService.workspace.findUniqueOrThrow({
|
const workspace =
|
||||||
where: { id: payload.workspaceId },
|
await this.prismaService.client.workspace.findUniqueOrThrow({
|
||||||
});
|
where: { id: payload.workspaceId },
|
||||||
|
});
|
||||||
|
|
||||||
if (!workspace) {
|
if (!workspace) {
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { CanActivate } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { CommentThreadService } from 'src/core/comment/services/comment-thread.service';
|
import { CommentThreadService } from 'src/core/comment/services/comment-thread.service';
|
||||||
import { CreateOneCommentGuard } from 'src/guards/create-one-comment.guard';
|
|
||||||
import { CreateOneCommentThreadGuard } from 'src/guards/create-one-comment-thread.guard';
|
|
||||||
import { AbilityFactory } from 'src/ability/ability.factory';
|
import { AbilityFactory } from 'src/ability/ability.factory';
|
||||||
|
|
||||||
import { CommentThreadResolver } from './comment-thread.resolver';
|
import { CommentThreadResolver } from './comment-thread.resolver';
|
||||||
@ -12,8 +9,6 @@ describe('CommentThreadResolver', () => {
|
|||||||
let resolver: CommentThreadResolver;
|
let resolver: CommentThreadResolver;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const mockGuard: CanActivate = { canActivate: jest.fn(() => true) };
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
CommentThreadResolver,
|
CommentThreadResolver,
|
||||||
@ -26,12 +21,7 @@ describe('CommentThreadResolver', () => {
|
|||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}).compile();
|
||||||
.overrideGuard(CreateOneCommentGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.overrideGuard(CreateOneCommentThreadGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
resolver = module.get<CommentThreadResolver>(CommentThreadResolver);
|
resolver = module.get<CommentThreadResolver>(CommentThreadResolver);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { Workspace } from 'src/core/@generated/workspace/workspace.model';
|
|||||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||||
import { CommentThread } from 'src/core/@generated/comment-thread/comment-thread.model';
|
import { CommentThread } from 'src/core/@generated/comment-thread/comment-thread.model';
|
||||||
import { CreateOneCommentThreadArgs } from 'src/core/@generated/comment-thread/create-one-comment-thread.args';
|
import { CreateOneCommentThreadArgs } from 'src/core/@generated/comment-thread/create-one-comment-thread.args';
|
||||||
import { CreateOneCommentThreadGuard } from 'src/guards/create-one-comment-thread.guard';
|
|
||||||
import { FindManyCommentThreadArgs } from 'src/core/@generated/comment-thread/find-many-comment-thread.args';
|
import { FindManyCommentThreadArgs } from 'src/core/@generated/comment-thread/find-many-comment-thread.args';
|
||||||
import { CommentThreadService } from 'src/core/comment/services/comment-thread.service';
|
import { CommentThreadService } from 'src/core/comment/services/comment-thread.service';
|
||||||
import { UpdateOneCommentThreadArgs } from 'src/core/@generated/comment-thread/update-one-comment-thread.args';
|
import { UpdateOneCommentThreadArgs } from 'src/core/@generated/comment-thread/update-one-comment-thread.args';
|
||||||
@ -35,7 +34,6 @@ import { DeleteManyCommentThreadArgs } from 'src/core/@generated/comment-thread/
|
|||||||
export class CommentThreadResolver {
|
export class CommentThreadResolver {
|
||||||
constructor(private readonly commentThreadService: CommentThreadService) {}
|
constructor(private readonly commentThreadService: CommentThreadService) {}
|
||||||
|
|
||||||
@UseGuards(CreateOneCommentThreadGuard)
|
|
||||||
@Mutation(() => CommentThread, {
|
@Mutation(() => CommentThread, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
@ -51,6 +49,15 @@ export class CommentThreadResolver {
|
|||||||
data: {
|
data: {
|
||||||
...args.data,
|
...args.data,
|
||||||
...{ workspace: { connect: { id: workspace.id } } },
|
...{ workspace: { connect: { id: workspace.id } } },
|
||||||
|
commentThreadTargets: args.data?.commentThreadTargets?.createMany
|
||||||
|
? {
|
||||||
|
createMany: {
|
||||||
|
data: args.data.commentThreadTargets.createMany.data.map(
|
||||||
|
(target) => ({ ...target, workspaceId: workspace.id }),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
select: prismaSelect.value,
|
select: prismaSelect.value,
|
||||||
} as Prisma.CommentThreadCreateArgs);
|
} as Prisma.CommentThreadCreateArgs);
|
||||||
@ -65,6 +72,7 @@ export class CommentThreadResolver {
|
|||||||
@CheckAbilities(UpdateCommentThreadAbilityHandler)
|
@CheckAbilities(UpdateCommentThreadAbilityHandler)
|
||||||
async updateOneCommentThread(
|
async updateOneCommentThread(
|
||||||
@Args() args: UpdateOneCommentThreadArgs,
|
@Args() args: UpdateOneCommentThreadArgs,
|
||||||
|
@AuthWorkspace() workspace: Workspace,
|
||||||
@PrismaSelector({ modelName: 'CommentThread' })
|
@PrismaSelector({ modelName: 'CommentThread' })
|
||||||
prismaSelect: PrismaSelect<'CommentThread'>,
|
prismaSelect: PrismaSelect<'CommentThread'>,
|
||||||
): Promise<Partial<CommentThread>> {
|
): Promise<Partial<CommentThread>> {
|
||||||
@ -84,7 +92,18 @@ export class CommentThreadResolver {
|
|||||||
}
|
}
|
||||||
const updatedCommentThread = await this.commentThreadService.update({
|
const updatedCommentThread = await this.commentThreadService.update({
|
||||||
where: args.where,
|
where: args.where,
|
||||||
data: args.data,
|
data: {
|
||||||
|
...args.data,
|
||||||
|
commentThreadTargets: args.data?.commentThreadTargets?.createMany
|
||||||
|
? {
|
||||||
|
createMany: {
|
||||||
|
data: args.data.commentThreadTargets.createMany.data.map(
|
||||||
|
(target) => ({ ...target, workspaceId: workspace.id }),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
select: prismaSelect.value,
|
select: prismaSelect.value,
|
||||||
} as Prisma.CommentThreadUpdateArgs);
|
} as Prisma.CommentThreadUpdateArgs);
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { CanActivate } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { CommentService } from 'src/core/comment/services/comment.service';
|
import { CommentService } from 'src/core/comment/services/comment.service';
|
||||||
import { CreateOneCommentGuard } from 'src/guards/create-one-comment.guard';
|
|
||||||
import { AbilityFactory } from 'src/ability/ability.factory';
|
import { AbilityFactory } from 'src/ability/ability.factory';
|
||||||
|
|
||||||
import { CommentResolver } from './comment.resolver';
|
import { CommentResolver } from './comment.resolver';
|
||||||
@ -11,8 +9,6 @@ describe('CommentResolver', () => {
|
|||||||
let resolver: CommentResolver;
|
let resolver: CommentResolver;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const mockGuard: CanActivate = { canActivate: jest.fn(() => true) };
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
CommentResolver,
|
CommentResolver,
|
||||||
@ -25,10 +21,7 @@ describe('CommentResolver', () => {
|
|||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}).compile();
|
||||||
.overrideGuard(CreateOneCommentGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
resolver = module.get<CommentResolver>(CommentResolver);
|
resolver = module.get<CommentResolver>(CommentResolver);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import { Workspace } from 'src/core/@generated/workspace/workspace.model';
|
|||||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||||
import { CreateOneCommentArgs } from 'src/core/@generated/comment/create-one-comment.args';
|
import { CreateOneCommentArgs } from 'src/core/@generated/comment/create-one-comment.args';
|
||||||
import { Comment } from 'src/core/@generated/comment/comment.model';
|
import { Comment } from 'src/core/@generated/comment/comment.model';
|
||||||
import { CreateOneCommentGuard } from 'src/guards/create-one-comment.guard';
|
|
||||||
import { CommentService } from 'src/core/comment/services/comment.service';
|
import { CommentService } from 'src/core/comment/services/comment.service';
|
||||||
import {
|
import {
|
||||||
PrismaSelector,
|
PrismaSelector,
|
||||||
@ -25,7 +24,6 @@ import { User } from 'src/core/@generated/user/user.model';
|
|||||||
export class CommentResolver {
|
export class CommentResolver {
|
||||||
constructor(private readonly commentService: CommentService) {}
|
constructor(private readonly commentService: CommentService) {}
|
||||||
|
|
||||||
@UseGuards(CreateOneCommentGuard)
|
|
||||||
@Mutation(() => Comment, {
|
@Mutation(() => Comment, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,33 +7,35 @@ export class CommentThreadTargetService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.commentThreadTarget.findFirst;
|
findFirst = this.prismaService.client.commentThreadTarget.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.commentThreadTarget.findFirstOrThrow;
|
findFirstOrThrow =
|
||||||
|
this.prismaService.client.commentThreadTarget.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.commentThreadTarget.findUnique;
|
findUnique = this.prismaService.client.commentThreadTarget.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.commentThreadTarget.findUniqueOrThrow;
|
findUniqueOrThrow =
|
||||||
|
this.prismaService.client.commentThreadTarget.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.commentThreadTarget.findMany;
|
findMany = this.prismaService.client.commentThreadTarget.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.commentThreadTarget.create;
|
create = this.prismaService.client.commentThreadTarget.create;
|
||||||
createMany = this.prismaService.commentThreadTarget.createMany;
|
createMany = this.prismaService.client.commentThreadTarget.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.commentThreadTarget.update;
|
update = this.prismaService.client.commentThreadTarget.update;
|
||||||
upsert = this.prismaService.commentThreadTarget.upsert;
|
upsert = this.prismaService.client.commentThreadTarget.upsert;
|
||||||
updateMany = this.prismaService.commentThreadTarget.updateMany;
|
updateMany = this.prismaService.client.commentThreadTarget.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.commentThreadTarget.delete;
|
delete = this.prismaService.client.commentThreadTarget.delete;
|
||||||
deleteMany = this.prismaService.commentThreadTarget.deleteMany;
|
deleteMany = this.prismaService.client.commentThreadTarget.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.commentThreadTarget.aggregate;
|
aggregate = this.prismaService.client.commentThreadTarget.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.commentThreadTarget.count;
|
count = this.prismaService.client.commentThreadTarget.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.commentThreadTarget.groupBy;
|
groupBy = this.prismaService.client.commentThreadTarget.groupBy;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,33 +7,33 @@ export class CommentThreadService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.commentThread.findFirst;
|
findFirst = this.prismaService.client.commentThread.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.commentThread.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.commentThread.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.commentThread.findUnique;
|
findUnique = this.prismaService.client.commentThread.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.commentThread.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.commentThread.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.commentThread.findMany;
|
findMany = this.prismaService.client.commentThread.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.commentThread.create;
|
create = this.prismaService.client.commentThread.create;
|
||||||
createMany = this.prismaService.commentThread.createMany;
|
createMany = this.prismaService.client.commentThread.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.commentThread.update;
|
update = this.prismaService.client.commentThread.update;
|
||||||
upsert = this.prismaService.commentThread.upsert;
|
upsert = this.prismaService.client.commentThread.upsert;
|
||||||
updateMany = this.prismaService.commentThread.updateMany;
|
updateMany = this.prismaService.client.commentThread.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.commentThread.delete;
|
delete = this.prismaService.client.commentThread.delete;
|
||||||
deleteMany = this.prismaService.commentThread.deleteMany;
|
deleteMany = this.prismaService.client.commentThread.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.commentThread.aggregate;
|
aggregate = this.prismaService.client.commentThread.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.commentThread.count;
|
count = this.prismaService.client.commentThread.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.commentThread.groupBy;
|
groupBy = this.prismaService.client.commentThread.groupBy;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,33 +7,33 @@ export class CommentService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.comment.findFirst;
|
findFirst = this.prismaService.client.comment.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.comment.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.comment.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.comment.findUnique;
|
findUnique = this.prismaService.client.comment.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.comment.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.comment.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.comment.findMany;
|
findMany = this.prismaService.client.comment.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.comment.create;
|
create = this.prismaService.client.comment.create;
|
||||||
createMany = this.prismaService.comment.createMany;
|
createMany = this.prismaService.client.comment.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.comment.update;
|
update = this.prismaService.client.comment.update;
|
||||||
upsert = this.prismaService.comment.upsert;
|
upsert = this.prismaService.client.comment.upsert;
|
||||||
updateMany = this.prismaService.comment.updateMany;
|
updateMany = this.prismaService.client.comment.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.comment.delete;
|
delete = this.prismaService.client.comment.delete;
|
||||||
deleteMany = this.prismaService.comment.deleteMany;
|
deleteMany = this.prismaService.client.comment.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.comment.aggregate;
|
aggregate = this.prismaService.client.comment.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.comment.count;
|
count = this.prismaService.client.comment.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.comment.groupBy;
|
groupBy = this.prismaService.client.comment.groupBy;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { CanActivate } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { UpdateOneGuard } from 'src/guards/update-one.guard';
|
|
||||||
import { DeleteManyGuard } from 'src/guards/delete-many.guard';
|
|
||||||
import { CreateOneGuard } from 'src/guards/create-one.guard';
|
|
||||||
import { AbilityFactory } from 'src/ability/ability.factory';
|
import { AbilityFactory } from 'src/ability/ability.factory';
|
||||||
|
|
||||||
import { CompanyService } from './company.service';
|
import { CompanyService } from './company.service';
|
||||||
@ -13,8 +9,6 @@ describe('CompanyResolver', () => {
|
|||||||
let resolver: CompanyResolver;
|
let resolver: CompanyResolver;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const mockGuard: CanActivate = { canActivate: jest.fn(() => true) };
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
CompanyResolver,
|
CompanyResolver,
|
||||||
@ -27,14 +21,7 @@ describe('CompanyResolver', () => {
|
|||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}).compile();
|
||||||
.overrideGuard(UpdateOneGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.overrideGuard(DeleteManyGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.overrideGuard(CreateOneGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
resolver = module.get<CompanyResolver>(CompanyResolver);
|
resolver = module.get<CompanyResolver>(CompanyResolver);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,9 +12,6 @@ import { UpdateOneCompanyArgs } from 'src/core/@generated/company/update-one-com
|
|||||||
import { CreateOneCompanyArgs } from 'src/core/@generated/company/create-one-company.args';
|
import { CreateOneCompanyArgs } from 'src/core/@generated/company/create-one-company.args';
|
||||||
import { AffectedRows } from 'src/core/@generated/prisma/affected-rows.output';
|
import { AffectedRows } from 'src/core/@generated/prisma/affected-rows.output';
|
||||||
import { DeleteManyCompanyArgs } from 'src/core/@generated/company/delete-many-company.args';
|
import { DeleteManyCompanyArgs } from 'src/core/@generated/company/delete-many-company.args';
|
||||||
import { UpdateOneGuard } from 'src/guards/update-one.guard';
|
|
||||||
import { DeleteManyGuard } from 'src/guards/delete-many.guard';
|
|
||||||
import { CreateOneGuard } from 'src/guards/create-one.guard';
|
|
||||||
import {
|
import {
|
||||||
PrismaSelect,
|
PrismaSelect,
|
||||||
PrismaSelector,
|
PrismaSelector,
|
||||||
@ -78,7 +75,6 @@ export class CompanyResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(UpdateOneGuard)
|
|
||||||
@Mutation(() => Company, {
|
@Mutation(() => Company, {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
@ -96,7 +92,6 @@ export class CompanyResolver {
|
|||||||
} as Prisma.CompanyUpdateArgs);
|
} as Prisma.CompanyUpdateArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(DeleteManyGuard)
|
|
||||||
@Mutation(() => AffectedRows, {
|
@Mutation(() => AffectedRows, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
@ -110,7 +105,6 @@ export class CompanyResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(CreateOneGuard)
|
|
||||||
@Mutation(() => Company, {
|
@Mutation(() => Company, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -8,35 +8,35 @@ export class CompanyService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.company.findFirst;
|
findFirst = this.prismaService.client.company.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.company.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.company.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.company.findUnique;
|
findUnique = this.prismaService.client.company.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.company.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.company.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.company.findMany;
|
findMany = this.prismaService.client.company.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.company.create;
|
create = this.prismaService.client.company.create;
|
||||||
createMany = this.prismaService.company.createMany;
|
createMany = this.prismaService.client.company.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.company.update;
|
update = this.prismaService.client.company.update;
|
||||||
upsert = this.prismaService.company.upsert;
|
upsert = this.prismaService.client.company.upsert;
|
||||||
updateMany = this.prismaService.company.updateMany;
|
updateMany = this.prismaService.client.company.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.company.delete;
|
delete = this.prismaService.client.company.delete;
|
||||||
deleteMany = this.prismaService.company.deleteMany;
|
deleteMany = this.prismaService.client.company.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.company.aggregate;
|
aggregate = this.prismaService.client.company.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.company.count;
|
count = this.prismaService.client.company.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.company.groupBy;
|
groupBy = this.prismaService.client.company.groupBy;
|
||||||
async createDefaultCompanies({ workspaceId }: { workspaceId: string }) {
|
async createDefaultCompanies({ workspaceId }: { workspaceId: string }) {
|
||||||
const companies = companiesSeed.map((company) => ({
|
const companies = companiesSeed.map((company) => ({
|
||||||
...company,
|
...company,
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { CanActivate } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { UpdateOneGuard } from 'src/guards/update-one.guard';
|
|
||||||
import { DeleteManyGuard } from 'src/guards/delete-many.guard';
|
|
||||||
import { CreateOneGuard } from 'src/guards/create-one.guard';
|
|
||||||
import { AbilityFactory } from 'src/ability/ability.factory';
|
import { AbilityFactory } from 'src/ability/ability.factory';
|
||||||
|
|
||||||
import { PersonService } from './person.service';
|
import { PersonService } from './person.service';
|
||||||
@ -13,8 +9,6 @@ describe('PersonResolver', () => {
|
|||||||
let resolver: PersonResolver;
|
let resolver: PersonResolver;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const mockGuard: CanActivate = { canActivate: jest.fn(() => true) };
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
PersonResolver,
|
PersonResolver,
|
||||||
@ -27,14 +21,7 @@ describe('PersonResolver', () => {
|
|||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}).compile();
|
||||||
.overrideGuard(UpdateOneGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.overrideGuard(DeleteManyGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.overrideGuard(CreateOneGuard)
|
|
||||||
.useValue(mockGuard)
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
resolver = module.get<PersonResolver>(PersonResolver);
|
resolver = module.get<PersonResolver>(PersonResolver);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,9 +20,6 @@ import { AffectedRows } from 'src/core/@generated/prisma/affected-rows.output';
|
|||||||
import { DeleteManyPersonArgs } from 'src/core/@generated/person/delete-many-person.args';
|
import { DeleteManyPersonArgs } from 'src/core/@generated/person/delete-many-person.args';
|
||||||
import { Workspace } from 'src/core/@generated/workspace/workspace.model';
|
import { Workspace } from 'src/core/@generated/workspace/workspace.model';
|
||||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||||
import { UpdateOneGuard } from 'src/guards/update-one.guard';
|
|
||||||
import { DeleteManyGuard } from 'src/guards/delete-many.guard';
|
|
||||||
import { CreateOneGuard } from 'src/guards/create-one.guard';
|
|
||||||
import {
|
import {
|
||||||
PrismaSelect,
|
PrismaSelect,
|
||||||
PrismaSelector,
|
PrismaSelector,
|
||||||
@ -95,7 +92,6 @@ export class PersonResolver {
|
|||||||
return `${parent.firstName ?? ''} ${parent.lastName ?? ''}`;
|
return `${parent.firstName ?? ''} ${parent.lastName ?? ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(UpdateOneGuard)
|
|
||||||
@Mutation(() => Person, {
|
@Mutation(() => Person, {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
@ -128,7 +124,6 @@ export class PersonResolver {
|
|||||||
} as Prisma.PersonUpdateArgs);
|
} as Prisma.PersonUpdateArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(DeleteManyGuard)
|
|
||||||
@Mutation(() => AffectedRows, {
|
@Mutation(() => AffectedRows, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
@ -142,7 +137,6 @@ export class PersonResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(CreateOneGuard)
|
|
||||||
@Mutation(() => Person, {
|
@Mutation(() => Person, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,35 +10,35 @@ export class PersonService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.person.findFirst;
|
findFirst = this.prismaService.client.person.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.person.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.person.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.person.findUnique;
|
findUnique = this.prismaService.client.person.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.person.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.person.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.person.findMany;
|
findMany = this.prismaService.client.person.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.person.create;
|
create = this.prismaService.client.person.create;
|
||||||
createMany = this.prismaService.person.createMany;
|
createMany = this.prismaService.client.person.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.person.update;
|
update = this.prismaService.client.person.update;
|
||||||
upsert = this.prismaService.person.upsert;
|
upsert = this.prismaService.client.person.upsert;
|
||||||
updateMany = this.prismaService.person.updateMany;
|
updateMany = this.prismaService.client.person.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.person.delete;
|
delete = this.prismaService.client.person.delete;
|
||||||
deleteMany = this.prismaService.person.deleteMany;
|
deleteMany = this.prismaService.client.person.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.person.aggregate;
|
aggregate = this.prismaService.client.person.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.person.count;
|
count = this.prismaService.client.person.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.person.groupBy;
|
groupBy = this.prismaService.client.person.groupBy;
|
||||||
async createDefaultPeople({
|
async createDefaultPeople({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
companies,
|
companies,
|
||||||
|
|||||||
@ -7,33 +7,35 @@ export class PipelineProgressService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.pipelineProgress.findFirst;
|
findFirst = this.prismaService.client.pipelineProgress.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.pipelineProgress.findFirstOrThrow;
|
findFirstOrThrow =
|
||||||
|
this.prismaService.client.pipelineProgress.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.pipelineProgress.findUnique;
|
findUnique = this.prismaService.client.pipelineProgress.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.pipelineProgress.findUniqueOrThrow;
|
findUniqueOrThrow =
|
||||||
|
this.prismaService.client.pipelineProgress.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.pipelineProgress.findMany;
|
findMany = this.prismaService.client.pipelineProgress.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.pipelineProgress.create;
|
create = this.prismaService.client.pipelineProgress.create;
|
||||||
createMany = this.prismaService.pipelineProgress.createMany;
|
createMany = this.prismaService.client.pipelineProgress.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.pipelineProgress.update;
|
update = this.prismaService.client.pipelineProgress.update;
|
||||||
upsert = this.prismaService.pipelineProgress.upsert;
|
upsert = this.prismaService.client.pipelineProgress.upsert;
|
||||||
updateMany = this.prismaService.pipelineProgress.updateMany;
|
updateMany = this.prismaService.client.pipelineProgress.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.pipelineProgress.delete;
|
delete = this.prismaService.client.pipelineProgress.delete;
|
||||||
deleteMany = this.prismaService.pipelineProgress.deleteMany;
|
deleteMany = this.prismaService.client.pipelineProgress.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.pipelineProgress.aggregate;
|
aggregate = this.prismaService.client.pipelineProgress.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.pipelineProgress.count;
|
count = this.prismaService.client.pipelineProgress.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.pipelineProgress.groupBy;
|
groupBy = this.prismaService.client.pipelineProgress.groupBy;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,35 +8,35 @@ export class PipelineStageService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.pipelineStage.findFirst;
|
findFirst = this.prismaService.client.pipelineStage.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.pipelineStage.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.pipelineStage.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.pipelineStage.findUnique;
|
findUnique = this.prismaService.client.pipelineStage.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.pipelineStage.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.pipelineStage.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.pipelineStage.findMany;
|
findMany = this.prismaService.client.pipelineStage.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.pipelineStage.create;
|
create = this.prismaService.client.pipelineStage.create;
|
||||||
createMany = this.prismaService.pipelineStage.createMany;
|
createMany = this.prismaService.client.pipelineStage.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.pipelineStage.update;
|
update = this.prismaService.client.pipelineStage.update;
|
||||||
upsert = this.prismaService.pipelineStage.upsert;
|
upsert = this.prismaService.client.pipelineStage.upsert;
|
||||||
updateMany = this.prismaService.pipelineStage.updateMany;
|
updateMany = this.prismaService.client.pipelineStage.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.pipelineStage.delete;
|
delete = this.prismaService.client.pipelineStage.delete;
|
||||||
deleteMany = this.prismaService.pipelineStage.deleteMany;
|
deleteMany = this.prismaService.client.pipelineStage.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.pipelineStage.aggregate;
|
aggregate = this.prismaService.client.pipelineStage.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.pipelineStage.count;
|
count = this.prismaService.client.pipelineStage.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.pipelineStage.groupBy;
|
groupBy = this.prismaService.client.pipelineStage.groupBy;
|
||||||
|
|
||||||
// Customs
|
// Customs
|
||||||
async createDefaultPipelineStages({
|
async createDefaultPipelineStages({
|
||||||
|
|||||||
@ -10,35 +10,35 @@ export class PipelineService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.pipeline.findFirst;
|
findFirst = this.prismaService.client.pipeline.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.pipeline.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.pipeline.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.pipeline.findUnique;
|
findUnique = this.prismaService.client.pipeline.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.pipeline.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.pipeline.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.pipeline.findMany;
|
findMany = this.prismaService.client.pipeline.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.pipeline.create;
|
create = this.prismaService.client.pipeline.create;
|
||||||
createMany = this.prismaService.pipeline.createMany;
|
createMany = this.prismaService.client.pipeline.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.pipeline.update;
|
update = this.prismaService.client.pipeline.update;
|
||||||
upsert = this.prismaService.pipeline.upsert;
|
upsert = this.prismaService.client.pipeline.upsert;
|
||||||
updateMany = this.prismaService.pipeline.updateMany;
|
updateMany = this.prismaService.client.pipeline.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.pipeline.delete;
|
delete = this.prismaService.client.pipeline.delete;
|
||||||
deleteMany = this.prismaService.pipeline.deleteMany;
|
deleteMany = this.prismaService.client.pipeline.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.pipeline.aggregate;
|
aggregate = this.prismaService.client.pipeline.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.pipeline.count;
|
count = this.prismaService.client.pipeline.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.pipeline.groupBy;
|
groupBy = this.prismaService.client.pipeline.groupBy;
|
||||||
|
|
||||||
// Customs
|
// Customs
|
||||||
async createDefaultPipeline({ workspaceId }: { workspaceId: string }) {
|
async createDefaultPipeline({ workspaceId }: { workspaceId: string }) {
|
||||||
|
|||||||
@ -19,35 +19,35 @@ export class UserService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.user.findFirst;
|
findFirst = this.prismaService.client.user.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.user.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.user.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.user.findUnique;
|
findUnique = this.prismaService.client.user.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.user.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.user.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.user.findMany;
|
findMany = this.prismaService.client.user.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.user.create;
|
create = this.prismaService.client.user.create;
|
||||||
createMany = this.prismaService.user.createMany;
|
createMany = this.prismaService.client.user.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.user.update;
|
update = this.prismaService.client.user.update;
|
||||||
upsert = this.prismaService.user.upsert;
|
upsert = this.prismaService.client.user.upsert;
|
||||||
updateMany = this.prismaService.user.updateMany;
|
updateMany = this.prismaService.client.user.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.user.delete;
|
delete = this.prismaService.client.user.delete;
|
||||||
deleteMany = this.prismaService.user.deleteMany;
|
deleteMany = this.prismaService.client.user.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.user.aggregate;
|
aggregate = this.prismaService.client.user.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.user.count;
|
count = this.prismaService.client.user.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.user.groupBy;
|
groupBy = this.prismaService.client.user.groupBy;
|
||||||
|
|
||||||
// Customs
|
// Customs
|
||||||
async createUser<T extends Prisma.UserCreateArgs>(
|
async createUser<T extends Prisma.UserCreateArgs>(
|
||||||
@ -68,7 +68,7 @@ export class UserService {
|
|||||||
assert(workspace, 'workspace is missing', BadRequestException);
|
assert(workspace, 'workspace is missing', BadRequestException);
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
const user = await this.prismaService.user.upsert({
|
const user = await this.prismaService.client.user.upsert({
|
||||||
where: {
|
where: {
|
||||||
email: args.data.email,
|
email: args.data.email,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -7,33 +7,34 @@ export class WorkspaceMemberService {
|
|||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.workspaceMember.findFirst;
|
findFirst = this.prismaService.client.workspaceMember.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.workspaceMember.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.workspaceMember.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.workspaceMember.findUnique;
|
findUnique = this.prismaService.client.workspaceMember.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.workspaceMember.findUniqueOrThrow;
|
findUniqueOrThrow =
|
||||||
|
this.prismaService.client.workspaceMember.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.workspaceMember.findMany;
|
findMany = this.prismaService.client.workspaceMember.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.workspaceMember.create;
|
create = this.prismaService.client.workspaceMember.create;
|
||||||
createMany = this.prismaService.workspaceMember.createMany;
|
createMany = this.prismaService.client.workspaceMember.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.workspaceMember.update;
|
update = this.prismaService.client.workspaceMember.update;
|
||||||
upsert = this.prismaService.workspaceMember.upsert;
|
upsert = this.prismaService.client.workspaceMember.upsert;
|
||||||
updateMany = this.prismaService.workspaceMember.updateMany;
|
updateMany = this.prismaService.client.workspaceMember.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.workspaceMember.delete;
|
delete = this.prismaService.client.workspaceMember.delete;
|
||||||
deleteMany = this.prismaService.workspaceMember.deleteMany;
|
deleteMany = this.prismaService.client.workspaceMember.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.workspaceMember.aggregate;
|
aggregate = this.prismaService.client.workspaceMember.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.workspaceMember.count;
|
count = this.prismaService.client.workspaceMember.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.workspaceMember.groupBy;
|
groupBy = this.prismaService.client.workspaceMember.groupBy;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,35 +19,35 @@ export class WorkspaceService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
findFirst = this.prismaService.workspace.findFirst;
|
findFirst = this.prismaService.client.workspace.findFirst;
|
||||||
findFirstOrThrow = this.prismaService.workspace.findFirstOrThrow;
|
findFirstOrThrow = this.prismaService.client.workspace.findFirstOrThrow;
|
||||||
|
|
||||||
findUnique = this.prismaService.workspace.findUnique;
|
findUnique = this.prismaService.client.workspace.findUnique;
|
||||||
findUniqueOrThrow = this.prismaService.workspace.findUniqueOrThrow;
|
findUniqueOrThrow = this.prismaService.client.workspace.findUniqueOrThrow;
|
||||||
|
|
||||||
findMany = this.prismaService.workspace.findMany;
|
findMany = this.prismaService.client.workspace.findMany;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
create = this.prismaService.workspace.create;
|
create = this.prismaService.client.workspace.create;
|
||||||
createMany = this.prismaService.workspace.createMany;
|
createMany = this.prismaService.client.workspace.createMany;
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
update = this.prismaService.workspace.update;
|
update = this.prismaService.client.workspace.update;
|
||||||
upsert = this.prismaService.workspace.upsert;
|
upsert = this.prismaService.client.workspace.upsert;
|
||||||
updateMany = this.prismaService.workspace.updateMany;
|
updateMany = this.prismaService.client.workspace.updateMany;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete = this.prismaService.workspace.delete;
|
delete = this.prismaService.client.workspace.delete;
|
||||||
deleteMany = this.prismaService.workspace.deleteMany;
|
deleteMany = this.prismaService.client.workspace.deleteMany;
|
||||||
|
|
||||||
// Aggregate
|
// Aggregate
|
||||||
aggregate = this.prismaService.workspace.aggregate;
|
aggregate = this.prismaService.client.workspace.aggregate;
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
count = this.prismaService.workspace.count;
|
count = this.prismaService.client.workspace.count;
|
||||||
|
|
||||||
// GroupBy
|
// GroupBy
|
||||||
groupBy = this.prismaService.workspace.groupBy;
|
groupBy = this.prismaService.client.workspace.groupBy;
|
||||||
|
|
||||||
// Customs
|
// Customs
|
||||||
async createDefaultWorkspace() {
|
async createDefaultWorkspace() {
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `workspaceId` to the `comment_thread_targets` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "comment_thread_targets" ADD COLUMN "workspaceId" TEXT NOT NULL;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "comment_thread_targets" ADD CONSTRAINT "comment_thread_targets_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "attachments" ADD CONSTRAINT "attachments_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -5,24 +5,33 @@ import {
|
|||||||
OnModuleInit,
|
OnModuleInit,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
import { createPrismaQueryEventHandler } from 'prisma-query-log';
|
import { createPrismaQueryEventHandler } from 'prisma-query-log';
|
||||||
|
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||||
|
|
||||||
// TODO: Check if this is still needed
|
// Prepare Prisma extenstion ability
|
||||||
if (!global.prisma) {
|
const createPrismaClient = (options: Prisma.PrismaClientOptions) => {
|
||||||
global.prisma = new PrismaClient();
|
const client = new PrismaClient(options);
|
||||||
}
|
|
||||||
export default global.prisma;
|
return client;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExtendedPrismaClient = ReturnType<typeof createPrismaClient>;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaService extends PrismaClient implements OnModuleInit {
|
export class PrismaService implements OnModuleInit {
|
||||||
private readonly logger = new Logger(PrismaService.name);
|
private readonly logger = new Logger(PrismaService.name);
|
||||||
|
private prismaClient!: ExtendedPrismaClient;
|
||||||
|
|
||||||
|
public get client(): ExtendedPrismaClient {
|
||||||
|
return this.prismaClient;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private readonly environmentService: EnvironmentService) {
|
constructor(private readonly environmentService: EnvironmentService) {
|
||||||
const debugMode = environmentService.isDebugMode();
|
const debugMode = environmentService.isDebugMode();
|
||||||
super({
|
|
||||||
|
this.prismaClient = createPrismaClient({
|
||||||
errorFormat: 'minimal',
|
errorFormat: 'minimal',
|
||||||
log: debugMode
|
log: debugMode
|
||||||
? [
|
? [
|
||||||
@ -44,16 +53,16 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
|||||||
colorParameter: '\u001B[90m',
|
colorParameter: '\u001B[90m',
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$on('query' as any, logHandler);
|
this.prismaClient.$on('query' as any, logHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit(): Promise<void> {
|
||||||
await this.$connect();
|
await this.prismaClient.$connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
async enableShutdownHooks(app: INestApplication) {
|
async enableShutdownHooks(app: INestApplication) {
|
||||||
this.$on('beforeExit', async () => {
|
this.prismaClient.$on('beforeExit', async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,8 +173,10 @@ model Workspace {
|
|||||||
/// @TypeGraphQL.omit(input: true, output: true)
|
/// @TypeGraphQL.omit(input: true, output: true)
|
||||||
deletedAt DateTime?
|
deletedAt DateTime?
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
Attachment Attachment[]
|
||||||
|
CommentThreadTarget CommentThreadTarget[]
|
||||||
|
|
||||||
@@map("workspaces")
|
@@map("workspaces")
|
||||||
}
|
}
|
||||||
@ -379,9 +381,12 @@ model CommentThreadTarget {
|
|||||||
/// @Validator.IsOptional()
|
/// @Validator.IsOptional()
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
|
|
||||||
commentThread CommentThread @relation(fields: [commentThreadId], references: [id], onDelete: Cascade)
|
commentThread CommentThread @relation(fields: [commentThreadId], references: [id], onDelete: Cascade)
|
||||||
commentThreadId String
|
commentThreadId String
|
||||||
|
/// @TypeGraphQL.omit(input: true, output: false)
|
||||||
|
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||||
|
/// @TypeGraphQL.omit(input: true, output: true)
|
||||||
|
workspaceId String
|
||||||
commentableType CommentableType
|
commentableType CommentableType
|
||||||
commentableId String
|
commentableId String
|
||||||
|
|
||||||
@ -515,6 +520,8 @@ model Attachment {
|
|||||||
activityId String
|
activityId String
|
||||||
activity CommentThread @relation(fields: [activityId], references: [id])
|
activity CommentThread @relation(fields: [activityId], references: [id])
|
||||||
|
|
||||||
|
/// @TypeGraphQL.omit(input: true, output: false)
|
||||||
|
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||||
/// @TypeGraphQL.omit(input: true, output: true)
|
/// @TypeGraphQL.omit(input: true, output: true)
|
||||||
workspaceId String
|
workspaceId String
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const seedComments = async (prisma: PrismaClient) => {
|
|||||||
update: {},
|
update: {},
|
||||||
create: {
|
create: {
|
||||||
id: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfb600',
|
id: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfb600',
|
||||||
|
workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
|
||||||
commentableType: 'Company',
|
commentableType: 'Company',
|
||||||
commentableId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfa408',
|
commentableId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfa408',
|
||||||
commentThreadId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfb400',
|
commentThreadId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfb400',
|
||||||
@ -68,6 +69,7 @@ export const seedComments = async (prisma: PrismaClient) => {
|
|||||||
update: {},
|
update: {},
|
||||||
create: {
|
create: {
|
||||||
id: 'twenty-fe256b39-3ec3-4fe3-8997-a76aa0bfb600',
|
id: 'twenty-fe256b39-3ec3-4fe3-8997-a76aa0bfb600',
|
||||||
|
workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
|
||||||
commentableType: 'Person',
|
commentableType: 'Person',
|
||||||
commentableId: 'twenty-755035db-623d-41fe-92e7-dd45b7c568e1',
|
commentableId: 'twenty-755035db-623d-41fe-92e7-dd45b7c568e1',
|
||||||
commentThreadId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfc408',
|
commentThreadId: 'twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfc408',
|
||||||
@ -103,6 +105,7 @@ export const seedComments = async (prisma: PrismaClient) => {
|
|||||||
update: {},
|
update: {},
|
||||||
create: {
|
create: {
|
||||||
id: 'twenty-dev-fe256b39-3ec3-4fe3-8997-a76aa0bfba00',
|
id: 'twenty-dev-fe256b39-3ec3-4fe3-8997-a76aa0bfba00',
|
||||||
|
workspaceId: 'twenty-dev-7ed9d212-1c25-4d02-bf25-6aeccf7ea420',
|
||||||
commentableType: 'Company',
|
commentableType: 'Company',
|
||||||
commentableId: 'twenty-dev-a674fa6c-1455-4c57-afaf-dd5dc086361e',
|
commentableId: 'twenty-dev-a674fa6c-1455-4c57-afaf-dd5dc086361e',
|
||||||
commentThreadId: 'twenty-dev-fe256b39-3ec3-4fe3-8997-b76aaabfb408',
|
commentThreadId: 'twenty-dev-fe256b39-3ec3-4fe3-8997-b76aaabfb408',
|
||||||
|
|||||||
@ -1,106 +0,0 @@
|
|||||||
import {
|
|
||||||
CanActivate,
|
|
||||||
ExecutionContext,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
Injectable,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CreateOneCommentThreadGuard implements CanActivate {
|
|
||||||
constructor(private prismaService: PrismaService) {}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
|
||||||
// TODO: type request
|
|
||||||
const request = gqlContext.getContext().req;
|
|
||||||
const args = gqlContext.getArgs();
|
|
||||||
|
|
||||||
const targets = args.data?.commentThreadTargets?.createMany?.data;
|
|
||||||
const comments = args.data?.comments?.createMany?.data;
|
|
||||||
const workspace = request.user.workspace;
|
|
||||||
|
|
||||||
if (!targets || targets.length === 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Missing commentThreadTargets' },
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await targets.map(async (target) => {
|
|
||||||
if (!target.commentableId || !target.commentableType) {
|
|
||||||
throw new HttpException(
|
|
||||||
{
|
|
||||||
reason:
|
|
||||||
'Missing commentThreadTarget.commentableId or commentThreadTarget.commentableType',
|
|
||||||
},
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!['Person', 'Company'].includes(target.commentableType)) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Invalid commentThreadTarget.commentableType' },
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetEntity = await this.prismaService[
|
|
||||||
target.commentableType
|
|
||||||
].findUnique({
|
|
||||||
where: { id: target.commentableId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!targetEntity || targetEntity.workspaceId !== workspace.id) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'CommentThreadTarget not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!comments) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await comments.map(async (comment) => {
|
|
||||||
if (!comment.authorId) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Missing comment.authorId' },
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const author = await this.prismaService.user.findUnique({
|
|
||||||
where: { id: comment.authorId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!author) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Comment.authorId not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userWorkspaceMember =
|
|
||||||
await this.prismaService.workspaceMember.findFirst({
|
|
||||||
where: { userId: author.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
!userWorkspaceMember ||
|
|
||||||
userWorkspaceMember.workspaceId !== workspace.id
|
|
||||||
) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'userWorkspaceMember.workspaceId not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
import {
|
|
||||||
CanActivate,
|
|
||||||
ExecutionContext,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
Injectable,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CreateOneCommentGuard implements CanActivate {
|
|
||||||
constructor(private prismaService: PrismaService) {}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
|
||||||
const request = gqlContext.getContext().req;
|
|
||||||
const args = gqlContext.getArgs();
|
|
||||||
|
|
||||||
const authorId = args.data?.author?.connect?.id;
|
|
||||||
const commentThreadId = args.data?.commentThread?.connect?.id;
|
|
||||||
|
|
||||||
if (!authorId || !commentThreadId) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Missing author or commentThread' },
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const author = await this.prismaService.user.findUnique({
|
|
||||||
where: { id: authorId },
|
|
||||||
});
|
|
||||||
|
|
||||||
const commentThread = await this.prismaService.commentThread.findUnique({
|
|
||||||
where: { id: commentThreadId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!author || !commentThread) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Author or commentThread not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userWorkspaceMember =
|
|
||||||
await this.prismaService.workspaceMember.findFirst({
|
|
||||||
where: { userId: author.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!userWorkspaceMember) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Author or commentThread not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const workspace = request.user.workspace;
|
|
||||||
|
|
||||||
if (
|
|
||||||
userWorkspaceMember.workspaceId !== workspace.id ||
|
|
||||||
commentThread.workspaceId !== workspace.id
|
|
||||||
) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Author or commentThread not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { CanActivate, Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CreateOneGuard implements CanActivate {
|
|
||||||
constructor(private prismaService: PrismaService) {}
|
|
||||||
|
|
||||||
async canActivate(): Promise<boolean> {
|
|
||||||
// TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { CanActivate, Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class DeleteManyGuard implements CanActivate {
|
|
||||||
constructor(private prismaService: PrismaService) {}
|
|
||||||
|
|
||||||
async canActivate(): Promise<boolean> {
|
|
||||||
// TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
import {
|
|
||||||
CanActivate,
|
|
||||||
ExecutionContext,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
Injectable,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
||||||
|
|
||||||
import { PrismaService } from 'src/database/prisma.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UpdateOneGuard implements CanActivate {
|
|
||||||
constructor(private prismaService: PrismaService) {}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
||||||
const gqlContext = GqlExecutionContext.create(context);
|
|
||||||
const request = gqlContext.getContext().req;
|
|
||||||
const entity = gqlContext.getArgByIndex(3).returnType?.name;
|
|
||||||
const args = gqlContext.getArgs();
|
|
||||||
|
|
||||||
if (!entity || !args.where?.id) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Invalid Request' },
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const object = await this.prismaService[entity].findUniqueOrThrow({
|
|
||||||
where: { id: args.where.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!object) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Record not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const workspace = request.user.workspace;
|
|
||||||
|
|
||||||
if (object.workspaceId !== workspace.id) {
|
|
||||||
throw new HttpException(
|
|
||||||
{ reason: 'Record not found' },
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,7 +15,7 @@ export class PrismaHealthIndicator extends HealthIndicator {
|
|||||||
|
|
||||||
async isDatabaseInstanceHealthy(key: string): Promise<HealthIndicatorResult> {
|
async isDatabaseInstanceHealthy(key: string): Promise<HealthIndicatorResult> {
|
||||||
try {
|
try {
|
||||||
await this.prismaService.$queryRaw`SELECT 1`;
|
await this.prismaService.client.$queryRaw`SELECT 1`;
|
||||||
return this.getStatus(key, true);
|
return this.getStatus(key, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new HealthCheckError('Prisma check failed', e);
|
throw new HealthCheckError('Prisma check failed', e);
|
||||||
|
|||||||
@ -1262,9 +1262,9 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@ucast/mongo2js" "^1.3.0"
|
"@ucast/mongo2js" "^1.3.0"
|
||||||
|
|
||||||
"@casl/prisma@^1.4.0":
|
"@casl/prisma@1.4.0":
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.npmjs.org/@casl/prisma/-/prisma-1.4.0.tgz"
|
resolved "https://registry.yarnpkg.com/@casl/prisma/-/prisma-1.4.0.tgz#0b446e272c2b1ab300de8958c39aa534e3a29db2"
|
||||||
integrity sha512-edDoBfm2aSww5HLyAqKmSYlGqCX06Bo8j+4P8hBNuIxmSO97Q1jEO8hkCzMThnucuGFEbNvUct1+K64CH2zTWQ==
|
integrity sha512-edDoBfm2aSww5HLyAqKmSYlGqCX06Bo8j+4P8hBNuIxmSO97Q1jEO8hkCzMThnucuGFEbNvUct1+K64CH2zTWQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ucast/core" "^1.10.0"
|
"@ucast/core" "^1.10.0"
|
||||||
@ -1945,12 +1945,12 @@
|
|||||||
"@paljs/types" "5.3.3"
|
"@paljs/types" "5.3.3"
|
||||||
"@prisma/internals" "^4.15.0"
|
"@prisma/internals" "^4.15.0"
|
||||||
|
|
||||||
"@prisma/client@^4.13.0":
|
"@prisma/client@4.13.0":
|
||||||
version "4.15.0"
|
version "4.13.0"
|
||||||
resolved "https://registry.npmjs.org/@prisma/client/-/client-4.15.0.tgz"
|
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.13.0.tgz#271d2b9756503ea17bbdb459c7995536cf2a6191"
|
||||||
integrity sha512-xnROvyABcGiwqRNdrObHVZkD9EjkJYHOmVdlKy1yGgI+XOzvMzJ4tRg3dz1pUlsyhKxXGCnjIQjWW+2ur+YXuw==
|
integrity sha512-YaiiICcRB2hatxsbnfB66uWXjcRw3jsZdlAVxmx0cFcTc/Ad/sKdHCcWSnqyDX47vAewkjRFwiLwrOUjswVvmA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/engines-version" "4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944"
|
"@prisma/engines-version" "4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a"
|
||||||
|
|
||||||
"@prisma/debug@4.15.0":
|
"@prisma/debug@4.15.0":
|
||||||
version "4.15.0"
|
version "4.15.0"
|
||||||
@ -1970,15 +1970,15 @@
|
|||||||
debug "4.3.4"
|
debug "4.3.4"
|
||||||
strip-ansi "6.0.1"
|
strip-ansi "6.0.1"
|
||||||
|
|
||||||
"@prisma/engines-version@4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944":
|
"@prisma/engines-version@4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a":
|
||||||
version "4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944"
|
version "4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a"
|
||||||
resolved "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944.tgz"
|
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a.tgz#ae338908d11685dee50e7683502d75442b955bf9"
|
||||||
integrity sha512-sVOig4tjGxxlYaFcXgE71f/rtFhzyYrfyfNFUsxCIEJyVKU9rdOWIlIwQ2NQ7PntvGnn+x0XuFo4OC1jvPJKzg==
|
integrity sha512-fsQlbkhPJf08JOzKoyoD9atdUijuGBekwoOPZC3YOygXEml1MTtgXVpnUNchQlRSY82OQ6pSGQ9PxUe4arcSLQ==
|
||||||
|
|
||||||
"@prisma/engines@4.15.0":
|
"@prisma/engines@4.13.0":
|
||||||
version "4.15.0"
|
version "4.13.0"
|
||||||
resolved "https://registry.npmjs.org/@prisma/engines/-/engines-4.15.0.tgz"
|
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.13.0.tgz#582a6b90b6efeb0f465984f1fe0e72a4afaaa5ae"
|
||||||
integrity sha512-FTaOCGs0LL0OW68juZlGxFtYviZa4xdQj/rQEdat2txw0s3Vu/saAPKjNVXfIgUsGXmQ72HPgNr6935/P8FNAA==
|
integrity sha512-HrniowHRZXHuGT9XRgoXEaP2gJLXM5RMoItaY2PkjvuZ+iHc0Zjbm/302MB8YsPdWozAPHHn+jpFEcEn71OgPw==
|
||||||
|
|
||||||
"@prisma/engines@4.16.0":
|
"@prisma/engines@4.16.0":
|
||||||
version "4.16.0"
|
version "4.16.0"
|
||||||
@ -7415,7 +7415,7 @@ pretty-format@^28.0.0, pretty-format@^28.1.3:
|
|||||||
|
|
||||||
prisma-nestjs-graphql@^18.0.2:
|
prisma-nestjs-graphql@^18.0.2:
|
||||||
version "18.0.2"
|
version "18.0.2"
|
||||||
resolved "https://registry.npmjs.org/prisma-nestjs-graphql/-/prisma-nestjs-graphql-18.0.2.tgz"
|
resolved "https://registry.yarnpkg.com/prisma-nestjs-graphql/-/prisma-nestjs-graphql-18.0.2.tgz#852b9386d2c26bad0bd82254a5cc2e483a96d5b5"
|
||||||
integrity sha512-Gh7DDXyzJQBKWkQwKOpSsXygxNkfUO+Bq7q79HZgoKa+/oUzi84Fh4bjzU1REki9635rmZC8F5MoVNTzKaUrnw==
|
integrity sha512-Gh7DDXyzJQBKWkQwKOpSsXygxNkfUO+Bq7q79HZgoKa+/oUzi84Fh4bjzU1REki9635rmZC8F5MoVNTzKaUrnw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/generator-helper" "^4.14.0"
|
"@prisma/generator-helper" "^4.14.0"
|
||||||
@ -7438,12 +7438,12 @@ prisma-query-log@^3.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@sqltools/formatter" "^1.2.3"
|
"@sqltools/formatter" "^1.2.3"
|
||||||
|
|
||||||
prisma@^4.13.0:
|
prisma@4.13.0:
|
||||||
version "4.15.0"
|
version "4.13.0"
|
||||||
resolved "https://registry.npmjs.org/prisma/-/prisma-4.15.0.tgz"
|
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.13.0.tgz#0b83f40acf50cd47d7463a135c4e9b275713e602"
|
||||||
integrity sha512-iKZZpobPl48gTcSZVawLMQ3lEy6BnXwtoMj7hluoGFYu2kQ6F9LBuBrUyF95zRVnNo8/3KzLXJXJ5TEnLSJFiA==
|
integrity sha512-L9mqjnSmvWIRCYJ9mQkwCtj4+JDYYTdhoyo8hlsHNDXaZLh/b4hR0IoKIBbTKxZuyHQzLopb/+0Rvb69uGV7uA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/engines" "4.15.0"
|
"@prisma/engines" "4.13.0"
|
||||||
|
|
||||||
process-nextick-args@~2.0.0:
|
process-nextick-args@~2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user