Skip to content

Commit

Permalink
fix: attempt to resolve notion resource parents (#2155)
Browse files Browse the repository at this point in the history
* notion: best effort to find a parent

* process missing parents

* folder for orphaned resources

* clean
  • Loading branch information
fontanierh authored Oct 17, 2023
1 parent e3630a7 commit f65e257
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 3 deletions.
43 changes: 40 additions & 3 deletions connectors/src/connectors/notion/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,17 +347,19 @@ export async function retrieveNotionConnectorPermissions({
return new Err(new Error("Connector not found"));
}

const parentId = parentInternalId || "workspace";

const [pages, dbs] = await Promise.all([
NotionPage.findAll({
where: {
connectorId,
parentId: parentInternalId || "workspace",
parentId,
},
}),
NotionDatabase.findAll({
where: {
connectorId,
parentId: parentInternalId || "workspace",
parentId,
},
}),
]);
Expand All @@ -379,6 +381,7 @@ export async function retrieveNotionConnectorPermissions({
},
}),
]);

const expandable = childPage || childDB ? true : false;

return {
Expand Down Expand Up @@ -416,13 +419,47 @@ export async function retrieveNotionConnectorPermissions({

const dbResources = await Promise.all(dbs.map((db) => getDbResources(db)));

const folderResources: ConnectorResource[] = [];
if (!parentInternalId) {
const [orphanedPagesCount, orphanedDbsCount] = await Promise.all([
NotionPage.count({
where: {
connectorId,
parentId: "unknown",
},
}),
NotionDatabase.count({
where: {
connectorId,
parentId: "unknown",
},
}),
]);

if (orphanedPagesCount + orphanedDbsCount > 0) {
// We also need to return a "fake" top-level folder call "Orphaned" to include resources
// we haven't been able to find a parent for.
folderResources.push({
provider: c.type,
// Orphaned resources in the database will have "unknown" as their parentId.
internalId: "unknown",
parentInternalId: null,
type: "folder",
title: "Orphaned Resources",
sourceUrl: null,
expandable: true,
permission: "read",
});
}
}

const resources = pageResources.concat(dbResources);

resources.sort((a, b) => {
return a.title.localeCompare(b.title);
});

return new Ok(resources);
return new Ok(resources.concat(folderResources));
}

export async function retrieveNotionResourcesTitles(
Expand Down
190 changes: 190 additions & 0 deletions connectors/src/connectors/notion/temporal/activities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,135 @@ export async function cacheDatabaseChildren({
};
}

async function resolveResourceParent({
parentId,
parentType,
pageId,
accessToken,
loggerArgs,
}: {
parentId: string;
parentType: NotionConnectorPageCacheEntry["parentType"];
pageId: string;
accessToken: string;
loggerArgs: Record<string, string | number>;
}): Promise<{
parentId: string;
parentType: NotionConnectorPageCacheEntry["parentType"];
}> {
const localLogger = logger.child({
...loggerArgs,
pageId,
});

if (parentType === "unknown" || parentType === "workspace") {
return {
parentId,
parentType,
};
}

if (parentType === "block") {
return {
parentId: "unknown",
parentType: "unknown",
};
}

let reachable = await isAccessibleAndUnarchived(
accessToken,
parentId,
parentType,
localLogger
);

if (reachable) {
return {
parentId,
parentType,
};
}

localLogger.info(
"Parent is not reachable -- attempting to find a better one."
);

// refetch the page in hopes of getting a valid parent
const page = await retrievePage({
accessToken,
pageId,
loggerArgs,
});

if (!page) {
logger.info("Could not retrieve page to find a better parent.");
return {
parentId: "unknown",
parentType: "unknown",
};
}

const parent = getPageOrBlockParent(page);
let newParentId = parent.id;
let newParentType = parent.type;

if (parent.type === "block") {
localLogger.info(
"Parent is a block, attempting to find a non-block parent."
);
const blockParent = await getBlockParentMemoized(
accessToken,
parent.id,
localLogger
);
if (!blockParent) {
localLogger.info("Could not retrieve block parent.");
return {
parentId: "unknown",
parentType: "unknown",
};
}
newParentId = blockParent.parentId;
newParentType = blockParent.parentType;
}

if (newParentType === "block") {
localLogger.warn("Could not find a valid non-block parent.");
return {
parentId: "unknown",
parentType: "unknown",
};
}

if (newParentType === "workspace" || newParentType === "unknown") {
return {
parentId: newParentId,
parentType: newParentType,
};
}

reachable = await isAccessibleAndUnarchived(
accessToken,
newParentId,
newParentType,
localLogger
);

if (reachable) {
logger.info("Found a new reachable parent.");
return {
parentId: newParentId,
parentType: newParentType,
};
}

localLogger.info("Could not find a reachable parent");
return {
parentId: "unknown",
parentType: "unknown",
};
}

export async function renderAndUpsertPageFromCache({
connectorId,
pageId,
Expand Down Expand Up @@ -1461,6 +1590,67 @@ export async function renderAndUpsertPageFromCache({
}
}

// checks if the parent is accessible. If not, attempts to refetch the page to hopefully get a
// valid parent. If that fails, returns "unknown" parent (i.e, orphaned node).
const resolvedParent = await resolveResourceParent({
parentId,
parentType,
pageId,
accessToken,
loggerArgs,
});

parentType = resolvedParent.parentType;
parentId = resolvedParent.parentId;

if (parentType === "page" || parentType === "database") {
// check if we have the parent page/DB in the DB already. If not, we need to add it
// to the cache of resources to check.
localLogger.info(
{ parentType, parentId },
"notionRenderAndUpsertPageFromCache: Retrieving parent page/DB from connectors DB."
);

let notionId: string | null = null;
if (parentType === "page") {
const existingParentPage = await NotionPage.findOne({
where: {
notionPageId: parentId,
connectorId: connector.id,
},
});
if (!existingParentPage) {
localLogger.info(
"notionRenderAndUpsertPageFromCache: Parent page not found in connectors DB."
);
notionId = parentId;
}
} else if (parentType === "database") {
const existingParentDatabase = await NotionDatabase.findOne({
where: {
notionDatabaseId: parentId,
connectorId: connector.id,
},
});
if (!existingParentDatabase) {
localLogger.info(
"notionRenderAndUpsertPageFromCache: Parent database not found in connectors DB."
);
notionId = parentId;
}
} else {
((_x: never) => void _x)(parentType);
}

if (notionId) {
await NotionConnectorResourcesToCheckCacheEntry.upsert({
notionId,
connectorId: connector.id,
resourceType: parentType,
});
}
}

localLogger.info(
"notionRenderAndUpsertPageFromCache: Retrieving Notion page from connectors DB."
);
Expand Down

0 comments on commit f65e257

Please sign in to comment.