8000 poc: create instagram event and context from facebook connector by chentsulin · Pull Request #788 · Yoctol/bottender · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

poc: create instagram event and context from facebook connector #788 8000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 60 additions & 32 deletions packages/bottender-facebook/src/FacebookConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
import FacebookClient from './FacebookClient';
import FacebookContext from './FacebookContext';
import FacebookEvent from './FacebookEvent';
import InstagramContext from './InstagramContext';
import InstagramEvent from './InstagramEvent';

type FacebookRequestBody = Record<string, any>;

Expand Down Expand Up @@ -64,12 +66,14 @@ export default class FacebookConnector
return 'facebook';
}

getUniqueSessionKey(event: FacebookEvent | MessengerEvent): string | null {
getUniqueSessionKey(
event: FacebookEvent | MessengerEvent | InstagramEvent
): string | null {
if (event instanceof MessengerEvent) {
return this._messengerConnector.getUniqueSessionKey(event);
}

// TODO: How to determine session key in facebook feed events
// TODO: How to determine session key in facebook feed events and instagram
return null;
}

Expand Down Expand Up @@ -108,45 +112,59 @@ export default class FacebookConnector

public mapRequestToEvents(
body: FacebookRequestBody
): (FacebookEvent | MessengerEvent)[] {
// TODO: returns InstagramEvent (object === 'instagram')
if (body.object !== 'page') {
return [];
): (FacebookEvent | MessengerEvent | InstagramEvent)[] {
if (body.object === 'instagram') {
return body.entry
.map((rawEvent: any) => {
const businessAccountId = rawEvent.id;
if (rawEvent.changes) {
return new InstagramEvent(rawEvent.changes[0], {
businessAccountId,
});
}

return null;
})
.filter((event: any) => event !== null);
}

return body.entry
.map((rawEvent: any) => {
const pageId = rawEvent.id;
if (rawEvent.messaging) {
return new MessengerEvent(rawEvent.messaging[0], {
pageId,
isStandby: false,
});
}

if (rawEvent.standby) {
return new MessengerEvent(rawEvent.standby[0], {
pageId,
isStandby: true,
});
}

if (rawEvent.changes) {
return new FacebookEvent(rawEvent.changes[0], { pageId });
}

return null;
})
.filter((event: any) => event !== null);
if (body.object === 'page') {
return body.entry
.map((rawEvent: any) => {
const pageId = rawEvent.id;
if (rawEvent.messaging) {
return new MessengerEvent(rawEvent.messaging[0], {
pageId,
isStandby: false,
});
}

if (rawEvent.standby) {
return new MessengerEvent(rawEvent.standby[0], {
pageId,
isStandby: true,
});
}

if (rawEvent.changes) {
return new FacebookEvent(rawEvent.changes[0], { pageId });
}

return null;
})
.filter((event: any) => event !== null);
}

return [];
}

public async createContext(params: {
event: FacebookEvent | MessengerEvent;
event: FacebookEvent | MessengerEvent | InstagramEvent;
session?: Session;
initialState?: Record<string, any>;
requestContext?: RequestContext;
emitter?: EventEmitter;
}): Promise<FacebookContext | MessengerContext> {
}): Promise<FacebookContext | MessengerContext | InstagramContext> {
let customAccessToken;

if (this._mapPageToAccessToken) {
Expand All @@ -169,6 +187,16 @@ export default class FacebookConnector
appId: this._appId,
});
}
if (params.event instanceof InstagramEvent) {
return new InstagramContext({
...params,
event: params.event,
client: this._client,
customAccessToken,
batchQueue: this._batchQueue,
appId: this._appId,
});
}
return new MessengerContext({
...params,
event: params.event,
Expand Down
85 changes: 85 additions & 0 deletions packages/bottender-facebook/src/InstagramContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { EventEmitter } from 'events';

import { Context, RequestContext } from 'bottender';
import { MessengerBatchQueue } from 'messenger-batch';

import FacebookClient from './FacebookClient';
import InstagramBatch from './InstagramBatch';
import InstagramEvent from './InstagramEvent';

// TODO: use exported type
type Session = Record<string, any>;

type Options = {
appId?: string;
client: FacebookClient;
event: InstagramEvent;
session?: Session;
initialState?: Record<string, any>;
requestContext?: RequestContext;
customAccessToken?: string;
batchQueue?: MessengerBatchQueue | null;
emitter?: EventEmitter;
};

export default class InstagramContext extends Context<
FacebookClient,
InstagramEvent
> {
_appId: string | undefined;

_customAccessToken: string | undefined;

_batchQueue: MessengerBatchQueue | undefined;

public constructor({
appId,
client,
event,
session,
initialState,
requestContext,
customAccessToken,
batchQueue,
emitter,
}: Options) {
super({ client, event, session, initialState, requestContext, emitter });
this._customAccessToken = customAccessToken;
this._batchQueue = batchQueue || undefined;
this._appId = appId;
}

/**
* The name of the platform.
*
*/
get platform(): 'instagram' {
return 'instagram';
}

/**
*
* @param text The text to be sent in the reply.
*/
public async sendText(text: string) {
//
}

/**
* @see https://developers.facebook.com/docs/instagram-api/guides/comment-moderation
*/

public async hideComment() {}

public async unhideComment() {}

public async deleteComment() {}

public async getReplies() {}

public async sendReplies() {}

public async disableComment() {}

public async enableComment() {}
}
91 changes: 91 additions & 0 deletions packages/bottender-facebook/src/InstagramEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export type InstagramRawEvent =
/**
* Sends a notification to your endpoint when an Instagram user comments on a media object owned by an Instagram Business or Creator Account.
*/
| {
field: 'comments';
value: Record<string, any>; // TODO
}
/**
* Sends a notification to your endpoint when an Instagram user @mentions an Instagram Business or Creator Account in a comment or caption on a media object not owned by the Business or Creator.
*/
| {
field: 'mentions';
value: {
commentId?: string;
mediaId: string;
};
}
/**
* Sends a notification to your endpoint when a story owned by an Instagram Business or Creator Account expires.
*/
| {
field: 'story_insights';
value: {
mediaId: string;
exits: number;
replies: number;
reach: number;
tapsForward: number;
tapsBack: number;
impressions: number;
};
};

export default class InstagramEvent {
_rawEvent: InstagramRawEvent;

_businessAccountId: string | undefined;

constructor(
rawEvent: InstagramRawEvent,
options: { businessAccountId?: string } = {}
) {
this._rawEvent = rawEvent;
this._businessAccountId = options.businessAccountId;
}

/**
* Underlying raw event from Instagram.
*
*/
get rawEvent(): InstagramRawEvent {
return this._rawEvent;
}

/**
* Determine if the event is a message event.
*
*/
get isMessage(): boolean {
return false;
}

/**
* Determine if the event is a message event which includes text.
*
*/
get isText(): boolean {
return false;
}

/**
* The text string from Instagram raw event.
*
*/
get text(): string | null {
return null;
}

get isComment(): boolean {
return this.rawEvent.field === 'comments';
}

get isMention(): boolean {
return this.rawEvent.field === 'mentions';
}

get isStoryInsights(): boolean {
return this.rawEvent.field === 'story_insights';
}
}
0