From f2516c4ef1ad4279a39c5ac35317acf7e3fbe98d Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Sun, 27 Jan 2019 14:03:45 -0600 Subject: [PATCH] feat: github listener session support (#14) --- src/listener/GithubListener.ts | 66 ++++++++++++++++++++++----------- src/listener/SessionListener.ts | 3 ++ src/utils/index.ts | 2 +- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/listener/GithubListener.ts b/src/listener/GithubListener.ts index a1ca6e6e8..d7b6193ab 100644 --- a/src/listener/GithubListener.ts +++ b/src/listener/GithubListener.ts @@ -3,13 +3,11 @@ import { Inject } from 'noicejs'; import { Repository } from 'typeorm'; import { BotServiceOptions, INJECT_STORAGE } from 'src/BotService'; -import { User } from 'src/entity/auth/User'; import { Message } from 'src/entity/Message'; -import { Session } from 'src/entity/Session'; import { Tick } from 'src/entity/Tick'; import { NotImplementedError } from 'src/error/NotImplementedError'; import { FetchOptions, ListenerData } from 'src/listener'; -import { BaseListener } from 'src/listener/BaseListener'; +import { SessionListener } from 'src/listener/SessionListener'; import { ServiceEvent } from 'src/Service'; import { doesExist, mustExist } from 'src/utils'; import { GithubClientData } from 'src/utils/github'; @@ -27,7 +25,7 @@ export interface GithubListenerData extends ListenerData { } @Inject(INJECT_STORAGE) -export class GithubListener extends BaseListener { +export class GithubListener extends SessionListener { protected readonly client: Octokit; protected readonly tickRepository: Repository; @@ -54,21 +52,34 @@ export class GithubListener extends BaseListener { throw new NotImplementedError(); } - public createSession(uid: string, user: User): Promise { - throw new NotImplementedError(); - } - - public getSession(uid: string): Promise { - throw new NotImplementedError(); - } - public async send(msg: Message): Promise { - // comment on github + const ctx = mustExist(msg.context); + const [owner, repo] = ctx.channel.id.split('/'); + const [type, issue] = ctx.channel.thread.split('/'); + const options = { + body: msg.body, + number: Number(issue), + owner, + repo, + }; + + if (type === 'issues') { + this.logger.debug(options, 'commenting on github issue'); + await this.client.issues.createComment(options); + return; + } else { + this.logger.warn({ issue, type }, 'unable to comment on github issue type'); + } } protected async fetchSince() { const since = await this.getLastUpdate(); + await this.tickRepository.save(new Tick({ + intervalId: this.id, + status: 0, + })); + for (const repo of this.data.repos) { const options = { owner: repo.owner, @@ -82,19 +93,21 @@ export class GithubListener extends BaseListener { this.logger.debug({ comments }, 'got github comments'); for (const comment of comments) { - const msg = await this.convertMessage(comment, repo); - await this.bot.receive(msg); + try { + const msg = await this.convertMessage(comment, repo); + await this.bot.receive(msg); + } catch (err) { + this.logger.error(err, 'error receiving github comment'); + } } } - - await this.tickRepository.save(new Tick({ - intervalId: this.id, - status: 0, - })); } protected async getLastUpdate() { const lastTick = await this.tickRepository.findOne({ + order: { + createdAt: 'DESC', + } as any, where: { intervalId: this.id, }, @@ -108,14 +121,23 @@ export class GithubListener extends BaseListener { } protected async convertMessage(msg: Octokit.IssuesListCommentsForRepoResponseItem, repo: GithubRepoOptions): Promise { + const [thread] = mustExist(/((issues|pull)\/\d+)/.exec(msg.html_url)); + const uid = msg.user.id.toString(); const context = await this.createContext({ channel: { id: `${repo.owner}/${repo.repo}`, - thread: msg.node_id, + thread, }, name: msg.user.login, - uid: msg.user.id.toString(), + uid, }); + + const session = await this.getSession(uid); + if (doesExist(session)) { + this.logger.debug({ context, msg, session }, 'attaching session to message context'); + context.user = session.user; + } + return new Message({ body: msg.body, context, diff --git a/src/listener/SessionListener.ts b/src/listener/SessionListener.ts index a1095f8da..17c267e03 100644 --- a/src/listener/SessionListener.ts +++ b/src/listener/SessionListener.ts @@ -1,3 +1,5 @@ +import { Inject } from 'noicejs'; + import { INJECT_CLOCK } from 'src/BaseService'; import { BotServiceOptions } from 'src/BotService'; import { User } from 'src/entity/auth/User'; @@ -12,6 +14,7 @@ import { Clock } from 'src/utils/Clock'; * A listener that tracks sessions. */ +@Inject(INJECT_CLOCK) export abstract class SessionListener extends BaseListener implements Listener { protected readonly clock: Clock; protected readonly sessions: Map; diff --git a/src/utils/index.ts b/src/utils/index.ts index 71bb00410..459487ad3 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -92,7 +92,7 @@ export function getMethods(value: TValue): Set return methods; } -export function mustExist(val: T | undefined): T { +export function mustExist(val: T | null | undefined): T { if (isNil(val)) { throw new NotFoundError(); }