Skip to content

Commit 22998ae

Browse files
committed
added file redirect endpoint
1 parent 17d3be3 commit 22998ae

File tree

4 files changed

+150
-2
lines changed

4 files changed

+150
-2
lines changed

src/api/notion.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ const fetchNotionData = async <T extends any>({
3333
"content-type": "application/json",
3434
...(notionToken && { cookie: `token_v2=${notionToken}` }),
3535
},
36+
3637
body: JSON.stringify(body),
3738
});
38-
39-
return res.json();
39+
40+
let json = await res.json()
41+
// console.log('fetchNotionData:', json)
42+
return json;
4043
};
4144

4245
export const fetchPageById = async (pageId: string, notionToken?: string) => {
@@ -78,6 +81,7 @@ export const fetchTableData = async (
7881
},
7982
notionToken,
8083
});
84+
// console.log('fetchTableData:', table)
8185
return table;
8286
};
8387

src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { Router, Method } from "tiny-request-router";
33

44
import { pageRoute } from "./routes/page";
55
import { tableRoute } from "./routes/table";
6+
import { collectionRoute } from "./routes/collection";
67
import { userRoute } from "./routes/user";
78
import { assetRoute } from "./routes/asset";
9+
import { fileRoute } from "./routes/file";
810
import { searchRoute } from "./routes/search";
911
import { createResponse } from "./response";
1012
import { getCacheKey } from "./get-cache-key";
@@ -25,9 +27,11 @@ const router = new Router<Handler>();
2527
router.options("*", () => new Response(null, { headers: corsHeaders }));
2628
router.get("/v1/page/:pageId", pageRoute);
2729
router.get("/v1/table/:pageId", tableRoute);
30+
router.get("/v1/collection/:pageId", collectionRoute);
2831
router.get("/v1/user/:userId", userRoute);
2932
router.get("/v1/search", searchRoute);
3033
router.get("/v1/asset", assetRoute);
34+
router.get("/v1/file", fileRoute);
3135

3236
router.get("*", async () =>
3337
createResponse(

src/routes/collection.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { fetchPageById, fetchTableData, fetchNotionUsers } from "../api/notion";
2+
import { parsePageId, getNotionValue } from "../api/utils";
3+
import {
4+
RowContentType,
5+
CollectionType,
6+
RowType,
7+
HandlerRequest,
8+
} from "../api/types";
9+
import { createResponse } from "../response";
10+
11+
export const getCollectionData = async (
12+
collection: CollectionType,
13+
collectionViewId: string,
14+
notionToken?: string,
15+
raw?: boolean
16+
) => {
17+
const table = await fetchTableData(
18+
collection.value.id,
19+
collectionViewId,
20+
notionToken
21+
);
22+
23+
24+
const collectionRows = collection.value.schema;
25+
const collectionColKeys = Object.keys(collectionRows);
26+
27+
const tableArr: RowType[] = table.result.blockIds.map(
28+
(id: string) => table.recordMap.block[id]
29+
);
30+
31+
const tableData = tableArr.filter(
32+
(b) =>
33+
b.value && b.value.properties && b.value.parent_id === collection.value.id
34+
);
35+
36+
type Row = { id: string;[key: string]: RowContentType };
37+
38+
const rows: Row[] = [];
39+
40+
for (const td of tableData) {
41+
let row: Row = { id: td.value.id };
42+
43+
for (const key of collectionColKeys) {
44+
const val = td.value.properties[key];
45+
if (val) {
46+
const schema = collectionRows[key];
47+
row[schema.name] = raw ? val : getNotionValue(val, schema.type, td);
48+
if (schema.type === "person" && row[schema.name]) {
49+
const users = await fetchNotionUsers(row[schema.name] as string[]);
50+
row[schema.name] = users as any;
51+
}
52+
}
53+
}
54+
rows.push(row);
55+
}
56+
57+
const name: String = collection.value.name.join('')
58+
59+
return { rows, schema: collectionRows, name };
60+
};
61+
62+
63+
64+
65+
66+
67+
export async function collectionRoute(req: HandlerRequest) {
68+
const pageId = parsePageId(req.params.pageId);
69+
const page = await fetchPageById(pageId!, req.notionToken);
70+
71+
if (!page.recordMap.collection)
72+
return createResponse(
73+
JSON.stringify({ error: "No table found on Notion page: " + pageId }),
74+
{},
75+
401
76+
);
77+
78+
const collection = Object.keys(page.recordMap.collection).map(
79+
(k) => page.recordMap.collection[k]
80+
)[0];
81+
82+
const views: any[] = []
83+
84+
const collectionView: {
85+
value: { id: CollectionType["value"]["id"] };
86+
} = Object.keys(page.recordMap.collection_view).map((k) => {
87+
88+
views.push(page.recordMap.collection_view[k]['value'])
89+
return page.recordMap.collection_view[k]
90+
})[0];
91+
92+
const tableData = await getCollectionData(
93+
collection,
94+
collectionView.value.id,
95+
req.notionToken
96+
);
97+
98+
// console.log('table data:', JSON.stringify(collectionView.value))
99+
// console.log('view:', JSON.stringify(page.recordMap))
100+
101+
// clean up the table order
102+
const tableProps = views[0].format.table_properties
103+
tableProps.map((tableCol, i) => {
104+
tableProps[i] = { ...tableProps[i], ...tableData.schema[tableCol['property']] }
105+
})
106+
107+
return createResponse({ ...tableData, columns: tableProps, sort: views[0].page_sort, collection: collection });
108+
}

src/routes/file.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { fetchNotionAsset } from "../api/notion";
2+
import { HandlerRequest } from "../api/types";
3+
import { createResponse } from "../response";
4+
5+
export async function fileRoute(req: HandlerRequest) {
6+
7+
let url = new URL(req.request.url)
8+
let fileUrl = url.searchParams.get('url')
9+
let blockId = url.searchParams.get('blockId')
10+
11+
if (!fileUrl || !blockId)
12+
return createResponse(
13+
{ error: 'Please supply a file URL and block ID: asset?url=[file-url]&blockId=[block ID]' },
14+
{ "Content-Type": "application/json" },
15+
400
16+
);
17+
18+
const asset:any = await fetchNotionAsset(fileUrl, blockId);
19+
20+
if (asset && asset.signedUrls && asset.signedUrls[0])
21+
return Response.redirect(
22+
asset.signedUrls[0],
23+
302
24+
);
25+
26+
return createResponse(
27+
{ error: 'File not found' },
28+
{ "Content-Type": "application/json" },
29+
400
30+
);
31+
}
32+

0 commit comments

Comments
 (0)