mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 16:51:38 +10:00
fix: get stats query
This commit is contained in:
@ -4,8 +4,8 @@ import { Trans } from '@lingui/macro';
|
|||||||
|
|
||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||||
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
|
||||||
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
||||||
|
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
||||||
import type { GetStatsInput } from '@documenso/lib/server-only/document/get-stats';
|
import type { GetStatsInput } from '@documenso/lib/server-only/document/get-stats';
|
||||||
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
||||||
import { parseToIntegerArray } from '@documenso/lib/utils/params';
|
import { parseToIntegerArray } from '@documenso/lib/utils/params';
|
||||||
|
|||||||
@ -16,8 +16,8 @@ ENV_FILES.forEach((file) => {
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './e2e',
|
testDir: './e2e',
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: false,
|
||||||
workers: '50%',
|
workers: 1,
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { TeamMemberRole } from '@documenso/prisma/client';
|
|
||||||
import type { Prisma, User } from '@documenso/prisma/client';
|
import type { Prisma, User } from '@documenso/prisma/client';
|
||||||
import { SigningStatus } from '@documenso/prisma/client';
|
import {
|
||||||
import { DocumentVisibility } from '@documenso/prisma/client';
|
DocumentVisibility,
|
||||||
|
RecipientRole,
|
||||||
|
SigningStatus,
|
||||||
|
TeamMemberRole,
|
||||||
|
} from '@documenso/prisma/client';
|
||||||
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
||||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||||
|
|
||||||
@ -103,25 +107,52 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
|
|||||||
_all: true,
|
_all: true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
createdAt,
|
|
||||||
teamId: null,
|
teamId: null,
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: ExtendedDocumentStatus.COMPLETED,
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: user.email,
|
||||||
|
documentDeletedAt: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: user.email,
|
||||||
|
documentDeletedAt: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
createdAt,
|
||||||
AND: [searchFilter],
|
AND: [searchFilter],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
// Not signed counts.
|
// Not signed counts (Inbox).
|
||||||
prisma.document.groupBy({
|
prisma.document.groupBy({
|
||||||
by: ['status'],
|
by: ['status'],
|
||||||
_count: {
|
_count: {
|
||||||
_all: true,
|
_all: true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
status: ExtendedDocumentStatus.PENDING,
|
status: {
|
||||||
|
not: ExtendedDocumentStatus.DRAFT,
|
||||||
|
},
|
||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
signingStatus: SigningStatus.NOT_SIGNED,
|
signingStatus: SigningStatus.NOT_SIGNED,
|
||||||
|
role: {
|
||||||
|
not: 'CC',
|
||||||
|
},
|
||||||
documentDeletedAt: null,
|
documentDeletedAt: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -136,34 +167,43 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
|
|||||||
_all: true,
|
_all: true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
createdAt,
|
|
||||||
User: {
|
|
||||||
email: {
|
|
||||||
not: user.email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OR: [
|
OR: [
|
||||||
|
{
|
||||||
|
userId: user.id,
|
||||||
|
teamId: null,
|
||||||
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
status: ExtendedDocumentStatus.PENDING,
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
signingStatus: SigningStatus.SIGNED,
|
signingStatus: SigningStatus.SIGNED,
|
||||||
|
role: {
|
||||||
|
not: 'CC',
|
||||||
|
},
|
||||||
documentDeletedAt: null,
|
documentDeletedAt: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
userId: user.id,
|
||||||
|
teamId: null,
|
||||||
|
status: ExtendedDocumentStatus.COMPLETED,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
status: ExtendedDocumentStatus.COMPLETED,
|
status: ExtendedDocumentStatus.COMPLETED,
|
||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
signingStatus: SigningStatus.SIGNED,
|
|
||||||
documentDeletedAt: null,
|
documentDeletedAt: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
createdAt,
|
||||||
AND: [searchFilter],
|
AND: [searchFilter],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -199,7 +239,6 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
|
|||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
signingStatus: SigningStatus.SIGNED,
|
|
||||||
documentDeletedAt: {
|
documentDeletedAt: {
|
||||||
gte: DateTime.now().minus({ days: 30 }).startOf('day').toJSDate(),
|
gte: DateTime.now().minus({ days: 30 }).startOf('day').toJSDate(),
|
||||||
},
|
},
|
||||||
@ -207,6 +246,7 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
AND: [searchFilter],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
@ -224,15 +264,7 @@ type GetTeamCountsOption = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getTeamCounts = async (options: GetTeamCountsOption) => {
|
const getTeamCounts = async (options: GetTeamCountsOption) => {
|
||||||
const {
|
const { createdAt, teamId, teamEmail, senderIds = [], currentTeamMemberRole, search } = options;
|
||||||
createdAt,
|
|
||||||
teamId,
|
|
||||||
teamEmail,
|
|
||||||
senderIds = [],
|
|
||||||
currentUserEmail,
|
|
||||||
currentTeamMemberRole,
|
|
||||||
search,
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
const userIdWhereClause: Prisma.DocumentWhereInput['userId'] =
|
const userIdWhereClause: Prisma.DocumentWhereInput['userId'] =
|
||||||
senderIds.length > 0
|
senderIds.length > 0
|
||||||
@ -241,113 +273,171 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
|
|||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const searchFilter: Prisma.DocumentWhereInput = {
|
const searchFilter: Prisma.DocumentWhereInput = search
|
||||||
|
? {
|
||||||
OR: [
|
OR: [
|
||||||
{ title: { contains: search, mode: 'insensitive' } },
|
{ title: { contains: search, mode: 'insensitive' } },
|
||||||
{ Recipient: { some: { name: { contains: search, mode: 'insensitive' } } } },
|
{ Recipient: { some: { name: { contains: search, mode: 'insensitive' } } } },
|
||||||
{ Recipient: { some: { email: { contains: search, mode: 'insensitive' } } } },
|
{ Recipient: { some: { email: { contains: search, mode: 'insensitive' } } } },
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
const visibilityFilters = [
|
const visibilityFilters = [
|
||||||
...match(currentTeamMemberRole)
|
match(currentTeamMemberRole)
|
||||||
.with(TeamMemberRole.ADMIN, () => [
|
.with(TeamMemberRole.ADMIN, () => ({
|
||||||
{ visibility: DocumentVisibility.EVERYONE },
|
visibility: {
|
||||||
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
in: [
|
||||||
{ visibility: DocumentVisibility.ADMIN },
|
DocumentVisibility.EVERYONE,
|
||||||
])
|
DocumentVisibility.MANAGER_AND_ABOVE,
|
||||||
.with(TeamMemberRole.MANAGER, () => [
|
DocumentVisibility.ADMIN,
|
||||||
{ visibility: DocumentVisibility.EVERYONE },
|
],
|
||||||
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
},
|
||||||
])
|
}))
|
||||||
.otherwise(() => [{ visibility: DocumentVisibility.EVERYONE }]),
|
.with(TeamMemberRole.MANAGER, () => ({
|
||||||
|
visibility: {
|
||||||
|
in: [DocumentVisibility.EVERYONE, DocumentVisibility.MANAGER_AND_ABOVE],
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.otherwise(() => ({ visibility: DocumentVisibility.EVERYONE })),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Owner counts (ALL)
|
||||||
const ownerCountsWhereInput: Prisma.DocumentWhereInput = {
|
const ownerCountsWhereInput: Prisma.DocumentWhereInput = {
|
||||||
userId: userIdWhereClause,
|
userId: userIdWhereClause,
|
||||||
createdAt,
|
createdAt,
|
||||||
OR: [
|
OR: [
|
||||||
{ teamId },
|
|
||||||
...(teamEmail ? [{ User: { email: teamEmail } }] : []),
|
|
||||||
{
|
{
|
||||||
AND: [
|
teamId,
|
||||||
{
|
|
||||||
visibility: {
|
|
||||||
in: visibilityFilters.map((filter) => filter.visibility),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Recipient: {
|
|
||||||
none: {
|
|
||||||
email: currentUserEmail,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Recipient: {
|
|
||||||
some: {
|
|
||||||
email: currentUserEmail,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
...searchFilter,
|
OR: visibilityFilters,
|
||||||
};
|
},
|
||||||
|
|
||||||
const notSignedCountsWhereInput: Prisma.DocumentWhereInput = {
|
|
||||||
userId: userIdWhereClause,
|
|
||||||
createdAt,
|
|
||||||
status: ExtendedDocumentStatus.PENDING,
|
|
||||||
OR: [
|
|
||||||
{ teamId },
|
|
||||||
...(teamEmail
|
...(teamEmail
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
status: {
|
||||||
|
not: ExtendedDocumentStatus.DRAFT,
|
||||||
|
},
|
||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
signingStatus: SigningStatus.NOT_SIGNED,
|
|
||||||
documentDeletedAt: null,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
OR: visibilityFilters,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
email: teamEmail,
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
],
|
],
|
||||||
deletedAt: null,
|
...searchFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Not signed counts (INBOX)
|
||||||
|
const notSignedCountsWhereInput: Prisma.DocumentWhereInput = teamEmail
|
||||||
|
? {
|
||||||
|
userId: userIdWhereClause,
|
||||||
|
createdAt,
|
||||||
|
status: {
|
||||||
|
not: ExtendedDocumentStatus.DRAFT,
|
||||||
|
},
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: teamEmail,
|
||||||
|
signingStatus: SigningStatus.NOT_SIGNED,
|
||||||
|
role: {
|
||||||
|
not: RecipientRole.CC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
OR: visibilityFilters,
|
||||||
|
...searchFilter,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
userId: userIdWhereClause,
|
||||||
|
createdAt,
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
OR: [{ id: -1 }], // Empty set if no team email
|
||||||
|
},
|
||||||
|
searchFilter,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Has signed counts (PENDING + COMPLETED)
|
||||||
const hasSignedCountsWhereInput: Prisma.DocumentWhereInput = {
|
const hasSignedCountsWhereInput: Prisma.DocumentWhereInput = {
|
||||||
userId: userIdWhereClause,
|
userId: userIdWhereClause,
|
||||||
createdAt,
|
createdAt,
|
||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
teamId,
|
teamId,
|
||||||
status: {
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
in: [ExtendedDocumentStatus.PENDING, ExtendedDocumentStatus.COMPLETED],
|
deletedAt: null,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
teamId,
|
||||||
|
status: ExtendedDocumentStatus.COMPLETED,
|
||||||
|
deletedAt: null,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
...(teamEmail
|
...(teamEmail
|
||||||
? [
|
? [
|
||||||
|
{
|
||||||
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
|
OR: [
|
||||||
{
|
{
|
||||||
Recipient: {
|
Recipient: {
|
||||||
some: {
|
some: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
signingStatus: SigningStatus.SIGNED,
|
signingStatus: SigningStatus.SIGNED,
|
||||||
documentDeletedAt: null,
|
role: {
|
||||||
|
not: RecipientRole.CC,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
status: {
|
|
||||||
in: [ExtendedDocumentStatus.PENDING, ExtendedDocumentStatus.COMPLETED],
|
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
email: teamEmail,
|
||||||
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: ExtendedDocumentStatus.COMPLETED,
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: teamEmail,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
email: teamEmail,
|
||||||
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
],
|
],
|
||||||
deletedAt: null,
|
...searchFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
const deletedCountsWhereInput: Prisma.DocumentWhereInput = {
|
const deletedCountsWhereInput: Prisma.DocumentWhereInput = {
|
||||||
@ -373,6 +463,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
],
|
],
|
||||||
|
...searchFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
|
|||||||
Reference in New Issue
Block a user