mirror of
https://github.com/docmost/docmost.git
synced 2026-05-25 12:04:35 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1615e0f4ad | |||
| 1cb2535de3 | |||
| 83bc273cb0 | |||
| c7beaa3742 | |||
| 4a228e5a51 | |||
| edff375476 | |||
| 95016b2bfc | |||
| ca83712364 | |||
| 39550fe906 |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.22.0",
|
"version": "0.22.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Group, Text } from "@mantine/core";
|
import { Group, Text } from "@mantine/core";
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { User } from "server/dist/database/types/entity.types";
|
import { IUser } from '@/features/user/types/user.types.ts';
|
||||||
|
|
||||||
interface UserInfoProps {
|
interface UserInfoProps {
|
||||||
user: User;
|
user: Partial<IUser>;
|
||||||
size?: string;
|
size?: string;
|
||||||
}
|
}
|
||||||
export function UserInfo({ user, size }: UserInfoProps) {
|
export function UserInfo({ user, size }: UserInfoProps) {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ function CommentListWithTabs() {
|
|||||||
const spaceRules = space?.membership?.permissions;
|
const spaceRules = space?.membership?.permissions;
|
||||||
const spaceAbility = useSpaceAbility(spaceRules);
|
const spaceAbility = useSpaceAbility(spaceRules);
|
||||||
|
|
||||||
|
|
||||||
const canComment: boolean = spaceAbility.can(
|
const canComment: boolean = spaceAbility.can(
|
||||||
SpaceCaslAction.Manage,
|
SpaceCaslAction.Manage,
|
||||||
SpaceCaslSubject.Page
|
SpaceCaslSubject.Page
|
||||||
@@ -179,6 +180,17 @@ function CommentListWithTabs() {
|
|||||||
userSpaceRole={space?.membership?.role}
|
userSpaceRole={space?.membership?.role}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{canComment && (
|
||||||
|
<>
|
||||||
|
<Divider my={4} />
|
||||||
|
<CommentEditorWithActions
|
||||||
|
commentId={comment.id}
|
||||||
|
onSave={handleAddReply}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.22.0",
|
"version": "0.22.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class CommentController {
|
|||||||
@AuthWorkspace() workspace: Workspace,
|
@AuthWorkspace() workspace: Workspace,
|
||||||
) {
|
) {
|
||||||
const page = await this.pageRepo.findById(createCommentDto.pageId);
|
const page = await this.pageRepo.findById(createCommentDto.pageId);
|
||||||
if (!page) {
|
if (!page || page.deletedAt) {
|
||||||
throw new NotFoundException('Page not found');
|
throw new NotFoundException('Page not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,10 @@ export class CommentController {
|
|||||||
throw new NotFoundException('Comment not found');
|
throw new NotFoundException('Comment not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ability = await this.spaceAbility.createForUser(user, comment.spaceId);
|
const ability = await this.spaceAbility.createForUser(
|
||||||
|
user,
|
||||||
|
comment.spaceId,
|
||||||
|
);
|
||||||
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
|
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,35 +261,7 @@ export class PageService {
|
|||||||
|
|
||||||
if (isDuplicateInSameSpace) {
|
if (isDuplicateInSameSpace) {
|
||||||
// For duplicate in same space, position right after the original page
|
// For duplicate in same space, position right after the original page
|
||||||
let siblingQuery = this.db
|
|
||||||
.selectFrom('pages')
|
|
||||||
.select(['position'])
|
|
||||||
.where('spaceId', '=', rootPage.spaceId)
|
|
||||||
.where('position', '>', rootPage.position);
|
|
||||||
|
|
||||||
if (rootPage.parentPageId) {
|
|
||||||
siblingQuery = siblingQuery.where(
|
|
||||||
'parentPageId',
|
|
||||||
'=',
|
|
||||||
rootPage.parentPageId,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
siblingQuery = siblingQuery.where('parentPageId', 'is', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextSibling = await siblingQuery
|
|
||||||
.orderBy('position', 'asc')
|
|
||||||
.limit(1)
|
|
||||||
.executeTakeFirst();
|
|
||||||
|
|
||||||
if (nextSibling) {
|
|
||||||
nextPosition = generateJitteredKeyBetween(
|
|
||||||
rootPage.position,
|
|
||||||
nextSibling.position,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
nextPosition = generateJitteredKeyBetween(rootPage.position, null);
|
nextPosition = generateJitteredKeyBetween(rootPage.position, null);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// For copy to different space, position at the end
|
// For copy to different space, position at the end
|
||||||
nextPosition = await this.nextPagePosition(spaceId);
|
nextPosition = await this.nextPagePosition(spaceId);
|
||||||
@@ -434,7 +406,10 @@ export class PageService {
|
|||||||
attachment.id,
|
attachment.id,
|
||||||
newAttachmentId,
|
newAttachmentId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
await this.storageService.copy(attachment.filePath, newPathFile);
|
await this.storageService.copy(attachment.filePath, newPathFile);
|
||||||
|
|
||||||
await this.db
|
await this.db
|
||||||
.insertInto('attachments')
|
.insertInto('attachments')
|
||||||
.values({
|
.values({
|
||||||
@@ -452,7 +427,14 @@ export class PageService {
|
|||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.log(err);
|
this.logger.error(
|
||||||
|
`Duplicate page: failed to copy attachment ${attachment.id}`,
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
// Continue with other attachments even if one fails
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class TrashCleanupService {
|
|||||||
@Interval('trash-cleanup', 24 * 60 * 60 * 1000) // every 24 hours
|
@Interval('trash-cleanup', 24 * 60 * 60 * 1000) // every 24 hours
|
||||||
async cleanupOldTrash() {
|
async cleanupOldTrash() {
|
||||||
try {
|
try {
|
||||||
this.logger.log('Starting trash cleanup job');
|
this.logger.debug('Starting trash cleanup job');
|
||||||
|
|
||||||
const retentionDate = new Date();
|
const retentionDate = new Date();
|
||||||
retentionDate.setDate(retentionDate.getDate() - this.RETENTION_DAYS);
|
retentionDate.setDate(retentionDate.getDate() - this.RETENTION_DAYS);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export class SearchService {
|
|||||||
.$if(Boolean(searchParams.creatorId), (qb) =>
|
.$if(Boolean(searchParams.creatorId), (qb) =>
|
||||||
qb.where('creatorId', '=', searchParams.creatorId),
|
qb.where('creatorId', '=', searchParams.creatorId),
|
||||||
)
|
)
|
||||||
|
.where('deletedAt', 'is', null)
|
||||||
.orderBy('rank', 'desc')
|
.orderBy('rank', 'desc')
|
||||||
.limit(searchParams.limit | 20)
|
.limit(searchParams.limit | 20)
|
||||||
.offset(searchParams.offset || 0);
|
.offset(searchParams.offset || 0);
|
||||||
@@ -191,6 +192,7 @@ export class SearchService {
|
|||||||
sql`LOWER(f_unaccent(${`%${query}%`}))`,
|
sql`LOWER(f_unaccent(${`%${query}%`}))`,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.where('deletedAt', 'is', null)
|
||||||
.where('workspaceId', '=', workspaceId)
|
.where('workspaceId', '=', workspaceId)
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
|
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ export class ShareService {
|
|||||||
includeCreator: true,
|
includeCreator: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
page.content = await this.updatePublicAttachments(page);
|
if (!page || page.deletedAt) {
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
throw new NotFoundException('Shared page not found');
|
throw new NotFoundException('Shared page not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page.content = await this.updatePublicAttachments(page);
|
||||||
|
|
||||||
return { page, share };
|
return { page, share };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +132,7 @@ export class ShareService {
|
|||||||
sql`0`.as('level'),
|
sql`0`.as('level'),
|
||||||
])
|
])
|
||||||
.where(isValidUUID(pageId) ? 'id' : 'slugId', '=', pageId)
|
.where(isValidUUID(pageId) ? 'id' : 'slugId', '=', pageId)
|
||||||
|
.where('deletedAt', 'is', null)
|
||||||
.unionAll((union) =>
|
.unionAll((union) =>
|
||||||
union
|
union
|
||||||
.selectFrom('pages as p')
|
.selectFrom('pages as p')
|
||||||
@@ -144,7 +145,8 @@ export class ShareService {
|
|||||||
// Increase the level by 1 for each ancestor.
|
// Increase the level by 1 for each ancestor.
|
||||||
sql`ph.level + 1`.as('level'),
|
sql`ph.level + 1`.as('level'),
|
||||||
])
|
])
|
||||||
.innerJoin('page_hierarchy as ph', 'ph.parentPageId', 'p.id'),
|
.innerJoin('page_hierarchy as ph', 'ph.parentPageId', 'p.id')
|
||||||
|
.where('p.deletedAt', 'is', null),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.selectFrom('page_hierarchy')
|
.selectFrom('page_hierarchy')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectKysely } from 'nestjs-kysely';
|
import { InjectKysely } from 'nestjs-kysely';
|
||||||
import { KyselyDB, KyselyTransaction } from '../../types/kysely.types';
|
import { KyselyDB, KyselyTransaction } from '../../types/kysely.types';
|
||||||
import { dbOrTx } from '../../utils';
|
import { dbOrTx, executeTx } from '../../utils';
|
||||||
import {
|
import {
|
||||||
InsertablePage,
|
InsertablePage,
|
||||||
Page,
|
Page,
|
||||||
@@ -183,7 +183,9 @@ export class PageRepo {
|
|||||||
|
|
||||||
const pageIds = descendants.map((d) => d.id);
|
const pageIds = descendants.map((d) => d.id);
|
||||||
|
|
||||||
await this.db
|
if (pageIds.length > 0) {
|
||||||
|
await executeTx(this.db, async (trx) => {
|
||||||
|
await trx
|
||||||
.updateTable('pages')
|
.updateTable('pages')
|
||||||
.set({
|
.set({
|
||||||
deletedById: deletedById,
|
deletedById: deletedById,
|
||||||
@@ -191,6 +193,10 @@ export class PageRepo {
|
|||||||
})
|
})
|
||||||
.where('id', 'in', pageIds)
|
.where('id', 'in', pageIds)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
await trx.deleteFrom('shares').where('pageId', 'in', pageIds).execute();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async restorePage(pageId: string): Promise<void> {
|
async restorePage(pageId: string): Promise<void> {
|
||||||
|
|||||||
+1
-1
Submodule apps/server/src/ee updated: 576cf4fa42...d39ddc4b5e
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "docmost",
|
"name": "docmost",
|
||||||
"homepage": "https://docmost.com",
|
"homepage": "https://docmost.com",
|
||||||
"version": "0.22.0",
|
"version": "0.22.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nx run-many -t build",
|
"build": "nx run-many -t build",
|
||||||
|
|||||||
Reference in New Issue
Block a user