notionboxdsync.ts4 matches
3334const notion = new Client({ auth: process.env.NOTION_SECRET! });
35const dbID = process.env.NOTION_DATABASE_ID!;
3637export default async function syncLetterboxd() {
69const page = await notion.pages.create({
70parent: {
71database_id: dbID,
72},
73108109async function existsByGUID(guid: string) {
110const res = await notion.databases.query(
111{
112database_id: dbID,
113page_size: 1,
114filter: {
67- `auth.ts` - Authentication middleware
8- `example-database-page.ts` - Handles `/example/database/page` endpoint
9- `example-guest-welcome.ts` - Handles `/example/guest/welcome` endpoint
10- `glancer.ts` - Handles `/glancer` and `/glancer/:id` endpoints
30// if the block associated to this blob no longer exists in notion
31// the blob should be deleted; the block id is in lastRun.id
32// and can be either a callout block or a child_database
33const block = await notion.blocks.retrieve({ block_id: lastRun?.id });
34// console.log(block);
GlancernotionHelpers.ts23 matches
7});
89export async function createDatabasePagesParallel(databaseId: string, pages: []) {
10const creations = pages.map((page) =>
11notion.pages.create({
12parent: { database_id: databaseId },
13properties: {
14"Website": {
42}
4344// delete all database rows
45export async function deleteAllDatabasePagesParallel(databaseId: string) {
46const pageIds = await notion.databases.query({
47database_id: databaseId,
48});
49// Step 2: Delete all pages in parallel
59}
6061export async function getDatabaseId(databaseTitle: string) {
62// getDatabaseId(databaseTitle)
63const database = await notion.databases
64.query({ filter: { property: "title", title: { equals: databaseTitle } } });
65return database.results[0].id;
66}
6768export async function getDatabaseTitle(databaseId: string) {
69// getDatabaseTitle(databaseId)
70const database = await notion.databases.retrieve({ database_id: databaseId });
71// console.log(database.title[0].plain_text);
72return database.title[0].plain_text;
73}
7475export async function getDatabaseParentPageId(databaseId: string) {
76let currentBlockId = databaseId;
7778while (true) {
121}
122123export async function findChildDatabaseBlocks(rootBlockId: string, blockIdentifier: string) {
124const matchingBlocks = [];
125140// }
141if (
142block.type === "child_database" && block.child_database?.title && (!block.archived || !block.in_trash)
143) {
144const databaseTitle = await helpers.slugify(block.child_database?.title.toLowerCase()) || "";
145const identifier = await helpers.slugify(blockIdentifier?.toLowerCase());
146147if (databaseTitle === identifier) {
148console.log(databaseTitle, identifier);
149matchingBlocks.push(block);
150}
Glancerexample-database-page.ts31 matches
20const data = payload?.data;
21const pageId = data?.id;
22const databaseId = data?.parent?.database_id;
2324// this endpoint is for a specific database page and is triggered by a button in that database page
2526// the button that calls this endpoint sends a payload with the id of the database page, and the id of the parent database
27// (e.g., pageId and databaseId from the payload)
2829// different than other endpoints, this one does not get called by a reset button or the cron reset
30// instead, the reset button and the reset cron target the database, not the page
31// so, we don't have a reset call coming in with the x-blob-key custom header to this enpoint
32// nor do we have a x-container-title header that holds the title of the target object coming from the button payload
3334// both the reset button and the reset cron delete all database pages, and then add back fresh pages
35// the endpoint for that is /example-database-pages (note the "s" at the end)
3637// different than other endpoints, we get the id of the block to modify (ie, the database page) from the button payload
38// so, we don't need to do the things we do at other endpoints to get the id of target block
39// (e.g., search the blob cache, or traverse notion page objects)
4041// but, we do need to set the blob for the resets
42// and for that we'll need the id of the page in which this database lives
43// and an identifier for the database
4445// can that idenfifier be the databaseId rather than the database title?
46// the reset button sends the database title to the .../pages endpoint in order to find the id of the database
47// but the matching there will traverse the notion page database objects looking for a title match
48// which has nothing to do with the database title in the blob
4950// note: if you're wondering why none of the notion buttons have hard-coded ids for the targeting
53// as is, i can clone a page with examples for a guest and everything will work without anyone needing to edit button settings
5455// when a user adds a favicon to a database page, we need to capture in the blob cache that a page in this database has been updated
56// so that resets know which database to reset
57// but the payload of the favicon button in this page does _not_ send the id of the page in which the database lives
58// nor does it send the database title
59// so we'll need to get those to make the blob key
6067for (const item of items) {
68const blobData = await blob.getJSON(item.key);
69if (blobData?.id === databaseId) {
70// console.log(item.key, blobData);
71blobData.key = item.key;
8283// blob for cache
84// get the parent page id of this child_database
85// this is the user's page and we need it for the blob key
86const parentPageId = blobject?.user
87? blobject?.user?.page_id
88: await notionHelpers.getDatabaseParentPageId(databaseId);
8990// we also need the database title
91// even though we have the database id and it's tempting to use it here
92// we need the title in the blob key so that the reset button can work
93// b/c the reset button can only send the title in the x-container-title header
94// with no other way to tie the button to the database
9596// const databaseTitle = blobject?.key
97// ? (blobject?.key).split("--").pop()
98// : await notionHelpers.getDatabaseTitle(databaseId);
99const databaseTitle = await notionHelpers.getDatabaseTitle(databaseId);
100101console.log("databaseTitle:", databaseTitle);
102103// store webhook data in blob storage for resets
105"slug": slug,
106"clientPageId": parentPageId,
107// "containerId": databaseId, // slugify databaseTitle here?
108"containerId": await helpers.slugify(databaseTitle),
109});
110await blob.setJSON(blobKey, {
113page_id: parentPageId,
114},
115id: databaseId,
116date: new Date(),
117content: askingFor,
Glancerexample-database-pages.ts9 matches
16const slug = await c.req.url.replace("https://", "");
17const askingFor = c.req.headers.get("x-asking-for") || "default"; // val.town or default
18const containerTitle = c.req.headers.get("x-container-title") || "good web sites"; // should map to the database title
19const payload = await c.req.json();
20const pageId = payload?.data?.id;
3839// when the reset button is clicked, it sends the x-container-title header
40// we use this header to a) find a blob or b) if no blob, find a database with a title that matches it
41// a) find a blob
42// b) find a database with a title that matches it
4344// blob
64// console.log("blockId:", blockId);
6566const databaseId = blobject?.id || (await notionHelpers.findChildDatabaseBlocks(pageId, containerTitle))[0].id;
67// console.log("databaseId:", databaseId);
6869// actions
70await notionHelpers.deleteAllDatabasePagesParallel(databaseId);
71// add back pages; fresh start for the next person to add favicons
72// create new database pages from default object
73await notionHelpers.createDatabasePagesParallel(databaseId, defaults);
74// store webhook data in blob storage for resets
75await blob.setJSON(blobKey, {
78page_id: pageId,
79},
80id: databaseId,
81date: new Date(),
82content: askingFor,
sqlite_adminREADME.md1 match
7It's currently super limited (no pagination, editing data, data-type specific viewers), and is just a couple dozens lines of code over a couple different vals. Forks encouraged! Just comment on the val if you add any features that you want to share.
89To use it on your own Val Town SQLite database, [fork it](https://www.val.town/v/stevekrouse/sqlite_admin/fork) to your account.
1011It uses [basic authentication](https://www.val.town/v/pomdtr/basicAuth) with your [Val Town API Token](https://www.val.town/settings/api) as the password (leave the username field blank).
ValTownForNotion1webhookAPI4 matches
7import exampleCallout from "./routes/example-callout.ts";
8import exampleChildPages from "./routes/example-child-pages.ts";
9import exampleDatabasePage from "./routes/example-database-page.ts";
10import exampleDatabasePages from "./routes/example-database-pages.ts";
11import exampleGuestWelcome from "./routes/example-guest-welcome.ts";
12import propertyInjections from "./routes/property-injections.ts";
2425// Mount route modules
26app.route("/example/database/pages", exampleDatabasePages);
27app.route("/example/database/page", exampleDatabasePage);
28app.route("/example/child_pages", exampleChildPages);
29app.route("/example/callout", exampleCallout);
ValTownForNotion1resets1 match
30// if the block associated to this blob no longer exists in notion
31// the blob should be deleted; the block id is in lastRun.id
32// and can be either a callout block or a child_database
33const block = await notion.blocks.retrieve({ block_id: lastRun?.id });
34// console.log(block);
ValTownForNotion1README.md1 match
3This val.town project catches webhooks from Notion, makes changes to the data payload, and sends those changes back to Notion as page updates.
45Here's one of the examples, which uses val.town to update database pages with favicons from the web:
67