Skip to content

Commit

Permalink
Merge pull request #5 from Nabhag8848/feat/NotionSDK
Browse files Browse the repository at this point in the history
[Feat] Notion Authorization with Rocket.Chat
  • Loading branch information
samad-yar-khan authored Jun 21, 2023
2 parents 6e916f1 + f9df28f commit e8cecc6
Show file tree
Hide file tree
Showing 39 changed files with 1,435 additions and 0 deletions.
87 changes: 87 additions & 0 deletions NotionApp.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,99 @@
import {
IAppAccessors,
IConfigurationExtend,
IEnvironmentRead,
IHttp,
ILogger,
IModify,
IPersistence,
IRead,
} from "@rocket.chat/apps-engine/definition/accessors";
import { App } from "@rocket.chat/apps-engine/definition/App";
import { IAppInfo } from "@rocket.chat/apps-engine/definition/metadata";
import { settings } from "./config/settings";
import { OAuth2Client } from "./src/authorization/OAuth2Client";
import { NotionCommand } from "./src/commands/NotionCommand";
import { NotionSDK } from "./src/lib/NotionSDK";
import {
ApiSecurity,
ApiVisibility,
} from "@rocket.chat/apps-engine/definition/api";
import { WebHookEndpoint } from "./src/endpoints/webhook";
import { ElementBuilder } from "./src/lib/ElementBuilder";
import { BlockBuilder } from "./src/lib/BlockBuilder";
import {
IUIKitResponse,
UIKitBlockInteractionContext,
} from "@rocket.chat/apps-engine/definition/uikit";
import { RoomInteractionStorage } from "./src/storage/RoomInteraction";
import { OAuth2Action } from "./enum/OAuth2";
import { IAppUtils } from "./definition/lib/IAppUtils";

export class NotionApp extends App {
private oAuth2Client: OAuth2Client;
private NotionSdk: NotionSDK;
private elementBuilder: ElementBuilder;
private blockBuilder: BlockBuilder;
constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) {
super(info, logger, accessors);
}

public async initialize(
configurationExtend: IConfigurationExtend,
environmentRead: IEnvironmentRead
): Promise<void> {
await configurationExtend.slashCommands.provideSlashCommand(
new NotionCommand(this)
);
await Promise.all(
settings.map((setting) => {
configurationExtend.settings.provideSetting(setting);
})
);

await configurationExtend.api.provideApi({
visibility: ApiVisibility.PUBLIC,
security: ApiSecurity.UNSECURE,
endpoints: [new WebHookEndpoint(this)],
});

this.oAuth2Client = new OAuth2Client(this);
this.NotionSdk = new NotionSDK(this.getAccessors().http);
this.elementBuilder = new ElementBuilder(this.getID());
this.blockBuilder = new BlockBuilder(this.getID());
}

public getOAuth2Client(): OAuth2Client {
return this.oAuth2Client;
}
public getUtils(): IAppUtils {
return {
NotionSdk: this.NotionSdk,
elementBuilder: this.elementBuilder,
blockBuilder: this.blockBuilder,
};
}

public async executeBlockActionHandler(
context: UIKitBlockInteractionContext,
read: IRead,
http: IHttp,
persistence: IPersistence,
modify: IModify
): Promise<IUIKitResponse> {
// Todo[Week 2]: Make a Interface and Class
const { actionId, user, room } = context.getInteractionData();

if (actionId == OAuth2Action.CONNECT_TO_WORKSPACE) {
const persistenceRead = read.getPersistenceReader();
const roomId = room?.id as string;
const roomInteraction = new RoomInteractionStorage(
persistence,
persistenceRead
);
await roomInteraction.storeInteractionRoomId(user.id, roomId);
}

return context.getInteractionResponder().successResponse();
}
}
38 changes: 38 additions & 0 deletions config/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
ISetting,
SettingType,
} from "@rocket.chat/apps-engine/definition/settings";

// The settings that will be available for the App
// warning(AppsEngine Error): Having OAuth2Setting in enums folder causing an error in deployment reason not known.
export enum OAuth2Setting {
CLIENT_ID = "notion-client-id",
CLIENT_SECRET = "notion-client-secret",
}

export const settings: Array<ISetting> = [
{
id: OAuth2Setting.CLIENT_ID,
type: SettingType.STRING,
packageValue: "",
required: true,
public: false,
section: "CredentialSettings",
i18nLabel: "ClientIdLabel",
i18nPlaceholder: "ClientIdPlaceholder",
hidden: false,
multiline: false,
},
{
id: OAuth2Setting.CLIENT_SECRET,
type: SettingType.PASSWORD,
packageValue: "",
required: true,
public: false,
section: "CredentialSettings",
i18nLabel: "ClientSecretLabel",
i18nPlaceholder: "ClientSecretPlaceholder",
hidden: false,
multiline: false,
},
];
5 changes: 5 additions & 0 deletions definition/authorization/ICredential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ICredential {
clientId: string;
clientSecret: string;
siteUrl: string;
}
39 changes: 39 additions & 0 deletions definition/authorization/IOAuth2Storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { NotionOwnerType, NotionTokenType } from "../../enum/Notion";

export interface IOAuth2Storage {
connectUserToWorkspace(
tokenInfo: ITokenInfo,
userId: string
): Promise<void>;
getCurrentWorkspace(userId: string): Promise<ITokenInfo | null>;
disconnectUserFromCurrentWorkspace(userId: string): Promise<ITokenInfo | null>;
}

export interface ITokenInfo {
access_token: string;
token_type: NotionTokenType.TOKEN_TYPE;
bot_id: string;
workspace_icon: string | null;
workspace_id: string;
workspace_name: string | null;
owner: INotionOwner;
duplicated_template_id: string | null;
}

interface INotionOwner {
type: NotionOwnerType.USER;
user: INotionUser;
}

interface INotionUser {
object: NotionOwnerType.USER;
id: string;
name: string | null;
avatar_url: string | null;
type: NotionOwnerType.PERSON;
person: INotionPerson;
}

interface INotionPerson {
email: string;
}
35 changes: 35 additions & 0 deletions definition/authorization/IOAuthClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
IHttp,
IModify,
IPersistence,
IRead,
} from "@rocket.chat/apps-engine/definition/accessors";
import { IRoom } from "@rocket.chat/apps-engine/definition/rooms";
import { IUser } from "@rocket.chat/apps-engine/definition/users";

export interface IOAuth2Client {
connect(
room: IRoom,
sender: IUser,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence
): Promise<void>;

disconnect(
room: IRoom,
sender: IUser,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence
): Promise<void>;

getAuthorizationUrl(
user: IUser,
read: IRead,
modify: IModify,
room: IRoom
): Promise<string | null>;
}
37 changes: 37 additions & 0 deletions definition/command/ICommandUtility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
IHttp,
IModify,
IPersistence,
IRead,
} from "@rocket.chat/apps-engine/definition/accessors";
import { IRoom } from "@rocket.chat/apps-engine/definition/rooms";
import { IUser } from "@rocket.chat/apps-engine/definition/users";
import { NotionApp } from "../../NotionApp";

export interface ICommandUtility {
app: NotionApp;
params: Array<string>;
sender: IUser;
room: IRoom;
read: IRead;
modify: IModify;
http: IHttp;
persis: IPersistence;
triggerId?: string;
threadId?: string;

resolveCommand(): Promise<void>;
}

export interface ICommandUtilityParams {
app: NotionApp;
params: Array<string>;
sender: IUser;
room: IRoom;
read: IRead;
modify: IModify;
http: IHttp;
persis: IPersistence;
triggerId?: string;
threadId?: string;
}
4 changes: 4 additions & 0 deletions definition/errors/IError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IError extends Error {
statusCode: number;
additionalInfo?: string;
}
9 changes: 9 additions & 0 deletions definition/lib/IAppUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BlockBuilder } from "../../src/lib/BlockBuilder";
import { ElementBuilder } from "../../src/lib/ElementBuilder";
import { NotionSDK } from "../../src/lib/NotionSDK";

export interface IAppUtils {
NotionSdk: NotionSDK;
elementBuilder: ElementBuilder;
blockBuilder: BlockBuilder;
}
19 changes: 19 additions & 0 deletions definition/lib/INotion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IHttp } from "@rocket.chat/apps-engine/definition/accessors";
import { URL } from "url";
import { ITokenInfo } from "../authorization/IOAuth2Storage";
import { ClientError } from "../../errors/Error";
import { NotionApi } from "../../enum/Notion";

export interface INotion {
baseUrl: string;
NotionVersion: string;
}

export interface INotionSDK extends INotion {
http: IHttp;
createToken(
redirectUrl: URL,
code: string,
credentials: string
): Promise<ITokenInfo | ClientError>;
}
5 changes: 5 additions & 0 deletions definition/lib/IRoomInteraction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IRoomInteractionStorage {
storeInteractionRoomId(userId: string, roomId: string): Promise<void>;
getInteractionRoomId(userId: string): Promise<string>;
clearInteractionRoomId(userId: string): Promise<void>;
}
3 changes: 3 additions & 0 deletions definition/ui-kit/Block/IActionBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ActionsBlock } from "@rocket.chat/ui-kit";

export type ActionBlockParam = Pick<ActionsBlock, "blockId" | "elements">;
20 changes: 20 additions & 0 deletions definition/ui-kit/Block/IBlockBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
SectionBlock,
ActionsBlock,
PreviewBlockBase,
PreviewBlockWithThumb,
ContextBlock,
} from "@rocket.chat/ui-kit";
import { SectionBlockParam } from "./ISectionBlock";
import { ActionBlockParam } from "./IActionBlock";
import { PreviewBlockParam } from "./IPreviewBlock";
import { ContextBlockParam } from "./IContextBlock";

export interface IBlockBuilder {
createSectionBlock(param: SectionBlockParam): SectionBlock;
createActionBlock(param: ActionBlockParam): ActionsBlock;
createPreviewBlock(
param: PreviewBlockParam
): PreviewBlockBase | PreviewBlockWithThumb;
createContextBlock(param: ContextBlockParam): ContextBlock;
}
7 changes: 7 additions & 0 deletions definition/ui-kit/Block/IContextBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ImageParam } from "../Element/IImageElement";
import { ImageElement } from "@rocket.chat/ui-kit";

export type ContextBlockParam = {
contextElements: Array<string | ImageElement>;
blockId?: string;
};
8 changes: 8 additions & 0 deletions definition/ui-kit/Block/IPreviewBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PreviewBlockWithThumb } from "@rocket.chat/ui-kit";

export type PreviewBlockParam = Partial<
Pick<PreviewBlockWithThumb, "footer" | "thumb">
> & {
title: Array<string>;
description: Array<string>;
};
6 changes: 6 additions & 0 deletions definition/ui-kit/Block/ISectionBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SectionBlock } from "@rocket.chat/ui-kit";

export type SectionBlockParam = Pick<SectionBlock, "accessory" | "blockId"> & {
text?: string;
fields?: Array<string>;
};
5 changes: 5 additions & 0 deletions definition/ui-kit/Element/IButtonElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ButtonElement } from "@rocket.chat/ui-kit";

export type ButtonParam = Pick<ButtonElement, "value" | "style" | "url"> & {
text: string;
};
14 changes: 14 additions & 0 deletions definition/ui-kit/Element/IElementBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ButtonStyle } from "@rocket.chat/apps-engine/definition/uikit";
import { ButtonElement, ImageElement } from "@rocket.chat/ui-kit";
import { ButtonParam } from "./IButtonElement";
import { ImageParam } from "./IImageElement";

export interface IElementBuilder {
addButton(
param: ButtonParam,
interaction: ElementInteractionParam
): ButtonElement;
addImage(param: ImageParam): ImageElement;
}

export type ElementInteractionParam = { blockId: string; actionId: string };
3 changes: 3 additions & 0 deletions definition/ui-kit/Element/IImageElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ImageElement } from "@rocket.chat/ui-kit";

export type ImageParam = Pick<ImageElement, "imageUrl" | "altText">;
4 changes: 4 additions & 0 deletions enum/CommandParam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum CommandParam {
CONNECT = "connect",
DISCONNECT = "disconnect",
}
8 changes: 8 additions & 0 deletions enum/Error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export enum ErrorName {
BAD_REQUEST = "Bad Request",
UNAUTHORIZED = "Unauthorized",
SERVER_ERROR = "Internal Server Error",
FORBIDDEN = "Forbidden",
MANY_REQUESTS = "Too Many Requests",
NOT_FOUND = "Not Found",
}
Loading

0 comments on commit e8cecc6

Please sign in to comment.