Skip to content

Commit d7c2cec

Browse files
committed
✨(backend) add blocks converter to y-provider
1 parent 1cdb6b6 commit d7c2cec

File tree

6 files changed

+97
-0
lines changed

6 files changed

+97
-0
lines changed

src/backend/core/services/converter_services.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,43 @@ def convert(self, text):
5151
raise ServiceUnavailableError(
5252
"Failed to connect to conversion service",
5353
) from err
54+
55+
def convert_blocks(self, blocks):
56+
"""Convert a list of blocks into our internal format using an external microservice."""
57+
58+
try:
59+
response = requests.post(
60+
f"{settings.Y_PROVIDER_API_BASE_URL}{settings.BLOCKS_CONVERSION_API_ENDPOINT}/",
61+
json={
62+
"blocks": blocks,
63+
},
64+
headers={
65+
"Authorization": self.auth_header,
66+
"Content-Type": "application/json",
67+
},
68+
timeout=settings.CONVERSION_API_TIMEOUT,
69+
verify=settings.CONVERSION_API_SECURE,
70+
)
71+
response.raise_for_status()
72+
conversion_response = response.json()
73+
74+
except requests.RequestException as err:
75+
raise ServiceUnavailableError(
76+
"Failed to connect to conversion service",
77+
) from err
78+
79+
except ValueError as err:
80+
raise InvalidResponseError(
81+
"Could not parse conversion service response"
82+
) from err
83+
84+
try:
85+
document_content = conversion_response[
86+
settings.CONVERSION_API_CONTENT_FIELD
87+
]
88+
except KeyError as err:
89+
raise MissingContentError(
90+
f"Response missing required field: {settings.CONVERSION_API_CONTENT_FIELD}"
91+
) from err
92+
93+
return document_content

src/backend/impress/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,11 @@ class Base(Configuration):
645645
environ_name="CONVERSION_API_ENDPOINT",
646646
environ_prefix=None,
647647
)
648+
BLOCKS_CONVERSION_API_ENDPOINT = values.Value(
649+
default="convert-blocks",
650+
environ_name="BLOCKS_CONVERSION_API_ENDPOINT",
651+
environ_prefix=None,
652+
)
648653
CONVERSION_API_CONTENT_FIELD = values.Value(
649654
default="content",
650655
environ_name="CONVERSION_API_CONTENT_FIELD",
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//import { PartialBlock } from '@blocknote/core';
2+
import { ServerBlockNoteEditor } from '@blocknote/server-util';
3+
import { Request, Response } from 'express';
4+
import * as Y from 'yjs';
5+
6+
import { logger, toBase64 } from '@/utils';
7+
8+
interface ConversionRequest {
9+
blocks: any; // TODO: PartialBlock
10+
}
11+
12+
interface ConversionResponse {
13+
content: string;
14+
}
15+
16+
interface ErrorResponse {
17+
error: string;
18+
}
19+
20+
export const convertBlocksHandler = async (
21+
req: Request<
22+
object,
23+
ConversionResponse | ErrorResponse,
24+
ConversionRequest,
25+
object
26+
>,
27+
res: Response<ConversionResponse | ErrorResponse>,
28+
) => {
29+
const blocks = req.body?.blocks;
30+
if (!blocks) {
31+
res.status(400).json({ error: 'Invalid request: missing content' });
32+
return;
33+
}
34+
35+
try {
36+
const editor = ServerBlockNoteEditor.create();
37+
38+
// Create a Yjs Document from blocks, and encode it as a base64 string
39+
const yDocument = editor.blocksToYDoc(blocks, 'document-store');
40+
const content = toBase64(Y.encodeStateAsUpdate(yDocument));
41+
42+
res.status(200).json({ content });
43+
} catch (e) {
44+
logger('conversion failed:', e);
45+
res.status(500).json({ error: 'An error occurred' });
46+
}
47+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './collaborationResetConnectionsHandler';
22
export * from './collaborationWSHandler';
33
export * from './convertHandler';
4+
export * from './convertBlocksHandler';
45
export * from './getDocumentConnectionInfoHandler';

src/frontend/servers/y-provider/src/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ export const routes = {
22
COLLABORATION_WS: '/collaboration/ws/',
33
COLLABORATION_RESET_CONNECTIONS: '/collaboration/api/reset-connections/',
44
CONVERT: '/api/convert/',
5+
CONVERT_BLOCKS: '/api/convert-blocks/',
56
COLLABORATION_GET_CONNECTIONS: '/collaboration/api/get-connections/',
67
};

src/frontend/servers/y-provider/src/servers/appServer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import expressWebsockets from 'express-ws';
88
import {
99
collaborationResetConnectionsHandler,
1010
collaborationWSHandler,
11+
convertBlocksHandler,
1112
convertHandler,
1213
getDocumentConnectionInfoHandler,
1314
} from '@/handlers';
@@ -61,6 +62,8 @@ export const initApp = () => {
6162
convertHandler,
6263
);
6364

65+
app.post(routes.CONVERT_BLOCKS, httpSecurity, convertBlocksHandler);
66+
6467
Sentry.setupExpressErrorHandler(app);
6568

6669
app.get('/ping', (req, res) => {

0 commit comments

Comments
 (0)