You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.4 KiB
231 lines
7.4 KiB
// import { Low, JSONFile } from 'lowdb';
|
|
import dotenv from 'dotenv';
|
|
dotenv.config();
|
|
|
|
import { Client as NotionClient } from '@notionhq/client';
|
|
import { Filter, RichText } from '@notionhq/client/build/src/api-types';
|
|
|
|
import { CreateText, GetAllTexts, UpdateCard, UpdateText } from './MiroHelper.js';
|
|
import { isEmptyOrSpaces, MiroSyncInfo, MiroWidgetInfo, ProcessMiroWidget, ProcessNotionBlock, ProcessNotionProperty, sleep } from './Utility.js';
|
|
|
|
// const adapter = new JSONFile<DBDataType>('db.json')
|
|
// const db = new Low<DBDataType>(adapter);
|
|
|
|
// Read data from JSON file, this will set db.data content
|
|
// (async () => await db.read())();
|
|
// db.data = db.data || { syncInfo: [] };
|
|
|
|
// (async () => await db.write())();//if db.json doesn't exist, write file will silent fail at program end
|
|
|
|
let miro_app_id = process.env.MIRO_APP_ID || "";
|
|
let notion_page = process.env.NOTION_PAGE || "";
|
|
let notion_token = process.env.NOTION_TOKEN || "";
|
|
let database_sync_page_count: Number = Number(process.env.DATABASE_SYNC_PAGE_COUNT) || 0;
|
|
let synced_property_arr = (process.env.SYNCED_PROPERTY || "").split(',');
|
|
let filter = (process.env.FILTER || "");
|
|
|
|
let verbose: Number = Number(process.env.VERBOSE) || 0;
|
|
|
|
console.log(synced_property_arr);
|
|
|
|
const notion = new NotionClient({ auth: notion_token })
|
|
|
|
const PrettyText = (textArr: RichText[]) => {
|
|
let str = textArr.reduce((all, cur) => `${all}${cur.plain_text}`, '');
|
|
return `${str}`;
|
|
}
|
|
|
|
let counter = 0;
|
|
let timestamp = 0;
|
|
let remaining = 0;
|
|
|
|
function MiroRateLimitCallback(rateLimitReset: number, rateLimitRemaining: number) {
|
|
timestamp = rateLimitReset;
|
|
remaining = rateLimitRemaining;
|
|
}
|
|
|
|
function GetTimer() {
|
|
return Date.now() / 1000 - timestamp;
|
|
}
|
|
|
|
function ShouldIgnore(str: string) {
|
|
return isEmptyOrSpaces(str) || str == "<p></p>";
|
|
}
|
|
|
|
let x = 0;
|
|
let y = 0;
|
|
const COLUME_WIDTH = 200;
|
|
const PART_OFFSET = 1000;
|
|
|
|
function NewRow() {
|
|
y += 120;
|
|
}
|
|
|
|
function ResetRow() {
|
|
y = 0;
|
|
}
|
|
|
|
function NewColume() {
|
|
x += COLUME_WIDTH;
|
|
}
|
|
|
|
function ResetColume() {
|
|
x = 0;
|
|
}
|
|
|
|
async function SyncNotion2Miro(notionInfo: NotionInfoType, miroInfo?: MiroSyncInfo, onCreated?: () => void) {
|
|
if (ShouldIgnore(notionInfo.text)) {
|
|
console.log(`\tskipping empty string block\n`);
|
|
return;
|
|
}
|
|
|
|
counter++;
|
|
|
|
await sleep(100);
|
|
if (counter % 10 == 0) {
|
|
console.log('sleep to prevent miro blocking');
|
|
await sleep(2000);
|
|
}
|
|
|
|
while (remaining <= 1000 && GetTimer() < 0) {
|
|
console.log(`sleep to prevent miro blocking, timer[${GetTimer().toFixed()}]`);
|
|
await sleep(1000);
|
|
}
|
|
|
|
console.log(`miro sync counter[${counter}] timer[${GetTimer().toFixed()}] remaining points[${remaining}]`);
|
|
|
|
if (miroInfo == undefined) return;
|
|
|
|
let notionPageId = notionInfo.pageId;
|
|
let notionPropertyId = notionInfo.propertyId;
|
|
|
|
let info = undefined;
|
|
if (notionPropertyId === undefined)
|
|
info = miroInfo[notionPageId] && miroInfo[notionPageId]["_"];
|
|
else
|
|
info = miroInfo[notionPageId] && miroInfo[notionPageId][notionPropertyId];
|
|
|
|
async function CreateOrUpdateInfo(info?: MiroWidgetInfo) {
|
|
if (info === undefined) {
|
|
console.log(`\tcreate text: ${notionInfo.text}\n`);
|
|
// CreateCard(notionInfo.text, { notionId: notionInfo.id });
|
|
await CreateText(notionInfo.text, { notionPageId, notionPropertyId }, x, y, MiroRateLimitCallback);
|
|
// db.data?.syncInfo.push({ notionId: id });
|
|
}
|
|
else {
|
|
switch (info.type) {//conversion?
|
|
case 'card':
|
|
console.log(`\tupdate miro card[${info.id}] ${notionInfo.text}\n`);
|
|
await UpdateCard(info.id, notionInfo.text, undefined, MiroRateLimitCallback);
|
|
break;
|
|
case 'text':
|
|
console.log(`\tupdate miro text[${info.id}] ${notionInfo.text}\n`);
|
|
await UpdateText(info.id, notionInfo.text, undefined, MiroRateLimitCallback);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let index = 0; index < 2; index++) {
|
|
if (info === undefined) {
|
|
await CreateOrUpdateInfo();
|
|
onCreated && onCreated();
|
|
if (index == 0) x += PART_OFFSET;
|
|
else x -= PART_OFFSET + COLUME_WIDTH;
|
|
}
|
|
else
|
|
await CreateOrUpdateInfo(info[index]);
|
|
|
|
}
|
|
}
|
|
|
|
// async function SyncNotionPage(pageId: string, miroWidgetInfo: MiroSyncInfo) {
|
|
// let blocks = await notion.blocks.children.list({ block_id: pageId });
|
|
|
|
// console.log(blocks);
|
|
// //TODO deal with pagination
|
|
// if (blocks == undefined) return;
|
|
// if (miroWidgetInfo == undefined) return;
|
|
|
|
// if (blocks.has_more)
|
|
// console.warn("Need to deal with paging results!!");
|
|
// if (verbose)
|
|
// console.log(JSON.stringify(blocks.results, null, "\t"));
|
|
|
|
// let processedBlocks = ProcessNotionBlock(blocks.results);
|
|
// for (var block of processedBlocks) {
|
|
// if (block == null) continue;
|
|
// if (block.richText == null) {
|
|
// if (block.id == null) continue;
|
|
// console.warn(`try to handle unsupported block[${block.id}]`);
|
|
// await SyncNotionDatabase(block.id, miroWidgetInfo);
|
|
// continue;
|
|
// }
|
|
// let text = PrettyText(block.richText);
|
|
// console.log(`block[${block.id}] notionInfo.text`);
|
|
// await SyncNotion2Miro({ pageId: block.id, text: `<p>${text}</p>` }, miroWidgetInfo);
|
|
// }
|
|
// }
|
|
|
|
async function SyncNotionDatabase(databaseId: string, miroWidgetInfo?: MiroSyncInfo) {
|
|
try {
|
|
let db = await notion.databases.retrieve({ database_id: databaseId });
|
|
console.log(`Processing Database: ${PrettyText(db.title)}`);
|
|
let _filter = JSON.parse(filter) as Filter;
|
|
console.log(filter);
|
|
let pages = await notion.databases.query({ database_id: databaseId, filter: _filter });
|
|
|
|
//TODO deal with pagination
|
|
if (pages == undefined) return;
|
|
if (miroWidgetInfo == undefined) return;
|
|
|
|
let count = 0;
|
|
for (let page of pages.results) {
|
|
let processedProperties = ProcessNotionProperty(Object.entries(page.properties));
|
|
for (let property of processedProperties) {
|
|
if (property == null) continue;
|
|
if (synced_property_arr.includes(property.name) == false) continue;
|
|
|
|
if (database_sync_page_count != 0 && count >= database_sync_page_count) continue;
|
|
count++;
|
|
|
|
let text = property.richText ? PrettyText(property.richText) : property.text;
|
|
text = text || "";
|
|
|
|
console.log(`property[${property.id}] ${text}`);
|
|
let notionInfo = { pageId: page.id, propertyId: property.id, text: `<p>${text}</p>` };
|
|
|
|
if (ShouldIgnore(text)) NewColume();
|
|
|
|
await SyncNotion2Miro(notionInfo, miroWidgetInfo, NewColume);
|
|
}
|
|
ResetColume();
|
|
NewRow();
|
|
}
|
|
} catch (err) {
|
|
} finally {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
(async () => {
|
|
try {
|
|
let collection = await GetAllTexts();
|
|
let info = ProcessMiroWidget(collection.data, miro_app_id);
|
|
|
|
// console.log(JSON.stringify(collection));
|
|
await SyncNotionDatabase(notion_page, info);
|
|
// await SyncNotionPage(notion_page, info);
|
|
|
|
// await db.write();
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
})();
|
|
|
|
type NotionInfoType = {
|
|
pageId: string,
|
|
propertyId?: string,
|
|
text: string
|
|
} |