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

4 years ago
// 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
}