import { IConnection } from "./IConnection" ; import { Appservice , Space } from "matrix-bot-sdk" ; import LogWrapper from "../LogWrapper" ; import { ReposGetResponseData } from "../Github/Types" ; import axios from "axios" ; import { GitHubDiscussionConnection } from "./GithubDiscussion" ; import { GithubInstance } from "../Github/GithubInstance" ; import { BaseConnection } from "./BaseConnection" ; const log = new LogWrapper ( "GitHubDiscussionSpace" ) ; export interface GitHubDiscussionSpaceConnectionState { owner : string ; repo : string ; } /**
 * Handles rooms connected to a github repo.
 */ export class GitHubDiscussionSpace extends BaseConnection implements IConnection { static readonly CanonicalEventType = "uk.half-shot.matrix-hookshot.github.discussion.space" ; static readonly LegacyCanonicalEventType = "uk.half-shot.matrix-github.discussion.space" ; static readonly EventTypes = [ GitHubDiscussionSpace . CanonicalEventType , GitHubDiscussionSpace . LegacyCanonicalEventType , ] ; static readonly QueryRoomRegex = /#github_disc_(.+)_(.+):.*/ ; static async onQueryRoom ( result , opts ) { if ( ! result || result . length < 2 ) { log . error ( `Invalid alias pattern '${ result }'` ) ; throw Error ( "Could not find issue" ) ; } const [ owner , repo ] = result . slice ( 1 ) ; log . info ( `Fetching ${ owner }/${ repo }` ) ; let repoRes ; const octokit = opts . githubInstance . getOctokitForRepo ( owner , repo ) ; try { repoRes = ( await octokit . repos . get ( { owner , repo , } ) ) . data ; if ( ! repoRes . owner ) { throw Error ( 'Repo has no owner!' ) ; } } catch ( ex ) { log . error ( "Failed to get repo:" , ex ) ; throw Error ( "Could not find repo" ) ; } const state = { owner : repoRes . owner . login . toLowerCase ( ) , repo : repoRes . name . toLowerCase ( ) , } ; let avatarUrl = undefined ; try { const profile = await octokit . users . getByUsername ( { username : owner , } ) ; if ( profile . data . avatar_url ) { const res = await axios . get ( profile . data . avatar_url as string , { responseType : 'arraybuffer' , } ) ; log . info ( `uploading ${ profile . data . avatar_url }` ) ; const contentType = res . headers [ "content-type" ] ; const mxcUrl = await opts . as . botClient . uploadContent ( Buffer . from ( res . data as ArrayBuffer ) , contentType , `avatar_${ profile . data . id }.png` ) ; avatarUrl = { type : "m.room.avatar" , state_key : "" , content : { url : mxcUrl , } , } ; } } catch ( ex ) { log . warn ( "Failed to get avatar for org:" , ex ) ; } return { visibility : "public" , name : `${ state . owner }/${ state . repo } Discussions` , topic : `GitHub discussion index for ${ state . owner }/${ state . repo }` , preset : 'public_chat' , room_alias_name : `github_disc_${ owner . toLowerCase ( ) }_${ repo . toLowerCase ( ) }` , initial_state : [ { type : this . CanonicalEventType , content : state , state_key : `${ state . owner }/${ state . repo }` , } , avatarUrl , { type : "m.room.history_visibility" , state_key : "" , content : { history_visibility : 'world_readable' , } , } , ] , creation_content : { type : "m.space" , } , power_level_content_override : { ban : 100 , events_default : 50 , invite : 50 , kick : 100 , notifications : { room : 100 , } , redact : 100 , state_default : 100 , users_default : 0 , } , } ; } constructor ( public readonly space , private state , stateKey ) { super ( space . roomId , stateKey , GitHubDiscussionSpace . CanonicalEventType ) ; } public isInterestedInStateEvent ( eventType , stateKey ) { return GitHubDiscussionSpace . EventTypes . includes ( eventType ) && this . stateKey === stateKey ; } public get repo ( ) { return this . state . repo . toLowerCase ( ) ; } public get owner ( ) { return this . state . owner . toLowerCase ( ) ; } public toString ( ) { return `GitHubDiscussionSpace ${ this . owner }/${ this . repo }` ; } public async onDiscussionCreated ( discussion ) { log . info ( `Adding connection to ${ this . toString ( ) }` ) ; await this . space . addChildRoom ( discussion . roomId ) ; } }