import * as CORS from 'cors' ; import * as crypto from "crypto" ; import { https , HttpsFunction , Response } from 'firebase-functions' ; import { enviroment } from '../environments/environment' ; import { onCreateEvent } from '../application/stats' ; import { GitHubClient } from '../client/github' ; import { Logger } from '../client/logger' ; import { GitHubContributorInput , GitHubContributorMapper } from '../mappers/github/index.mapper' ; import { CreateEventModel , IssuesEventModel , IssueCommentEventModel , MemberEventModel , MilestoneEventModel , PullRequestEventModel , PushEventModel , ReleaseEventModel , RepositoryEventModel , StatusEventModel , WatchEventModel , } from '../mappers/github/webhook-event-response' ; import { addHubEventToCollection , HubEventActions } from '../mappers/github/webhook-event-response/shared' ; import { RepositoryModel } from '../models/index.model' ; import { DocumentData , FieldPath , FirebaseAdmin , QuerySnapshot } from './../client/firebase-admin' ; import { getPullRequestStatus } from './pull-request' ; const cors = CORS ( { origin : true , } ) ; export interface ResponseGitWebhookRepositoryInput { token : string ; repositoryUid : string ; } export const onResponseGitWebhookRepository = https . onRequest ( ( req , res ) => { return cors ( req , res , ( ) => { const sig = 'sha1=' + crypto . createHmac ( 'sha1' , enviroment . githubWebhook . secret ) . update ( req . rawBody ) . digest ( 'hex' ) ; if ( sig !== req . headers [ 'x-hub-signature' ] ) { res . status ( 401 ) . send ( 'Error secret token!' ) ; return ; } const inputData = req . body ; let result ; Logger . info ( Object . keys ( inputData ) ) ; Logger . info ( inputData ) ; if ( IssueCommentEventModel . isCurrentModel ( inputData ) ) { result = issueCommentEvent ( new IssueCommentEventModel ( inputData ) ) ; } else if ( IssuesEventModel . isCurrentModel ( inputData ) ) { result = issuesEvent ( new IssuesEventModel ( inputData ) ) ; } else if ( CreateEventModel . isCurrentModel ( inputData ) ) { result = createEvent ( new CreateEventModel ( inputData ) ) ; } else if ( PushEventModel . isCurrentModel ( inputData ) ) { result = pushEvent ( new PushEventModel ( inputData ) ) ; } else if ( PullRequestEventModel . isCurrentModel ( inputData ) ) { result = pullRequestEvent ( new PullRequestEventModel ( inputData ) ) ; } else if ( ReleaseEventModel . isCurrentModel ( inputData ) ) { result = releaseEvent ( new ReleaseEventModel ( inputData ) ) ; } else if ( MilestoneEventModel . isCurrentModel ( inputData ) ) { result = milestoneEvent ( new MilestoneEventModel ( inputData ) ) ; } else if ( WatchEventModel . isCurrentModel ( inputData ) ) { result = watchEvent ( new WatchEventModel ( inputData ) ) ; } else if ( RepositoryEventModel . isCurrentModel ( inputData ) ) { result = repositoryEvent ( new RepositoryEventModel ( inputData ) ) ; } else if ( MemberEventModel . isCurrentModel ( inputData ) ) { result = memberEvent ( new MemberEventModel ( inputData ) ) ; } else if ( StatusEventModel . isCurrentModel ( inputData ) ) { result = statusEvent ( new StatusEventModel ( inputData ) ) ; } else { Logger . error ( 'Not found parser for event' ) ; } if ( result ) { result . then ( ( ) => { Logger . info ( 'Parsing done!' ) ; onCreateEvent ( ) ; res . status ( 200 ) . send ( ) ; } ) . catch ( ( err ) => { Logger . error ( 'Parser error!' ) ; Logger . error ( err ) ; res . status ( 500 ) . send ( 'Parser error!' ) ; } ) ; } else { res . status ( 200 ) . send ( 'Not found parser for event' ) ; } } ) ; } ) ; async function simpleHubEvent ( data ) { const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; addHubEventToCollection ( repository , data ) ; await RepositoryModel . saveRepository ( repository ) ; } async function issuesEvent ( data ) { Logger . info ( 'issuesEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; data . updateData ( repository ) ; addHubEventToCollection ( repository , data ) ; await RepositoryModel . saveRepository ( repository ) ; } async function repositoryEvent ( data ) { Logger . info ( 'repositoryEvent' ) ; await data . updateData ( ) ; } async function pullRequestEvent ( data ) { Logger . info ( 'pullRequestEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; data . updateData ( repository ) ; const usersRef = await ( FirebaseAdmin . firestore ( ) . collection ( 'users' ) . where ( 'username' , '==' , data . sender . login ) . get ( ) ) ; for ( const element of usersRef . docs ) { const userData = element . data ( ) ; const githubToken = userData && userData . oauth ? userData . oauth . githubToken : null ; const ref = data . pull_request . statuses_url . split ( '/' ) . pop ( ) ; await getPullRequestStatus ( githubToken , repository . fullName , ref , repository . uid , data . pull_request . id ) ; } addHubEventToCollection ( repository , data ) ; await RepositoryModel . saveRepository ( repository ) ; } async function releaseEvent ( data ) { Logger . info ( 'releaseEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; data . updateData ( repository ) ; addHubEventToCollection ( repository , data ) ; await RepositoryModel . saveRepository ( repository ) ; } async function milestoneEvent ( data ) { Logger . info ( 'milestoneEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; data . updateData ( repository ) ; await RepositoryModel . saveRepository ( repository ) ; } async function watchEvent ( data ) { Logger . info ( 'watchEvent' ) ; await simpleHubEvent ( data ) ; } async function pushEvent ( data ) { Logger . info ( 'pushEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; addHubEventToCollection ( repository , data ) ; await updateContributors ( repository ) ; await RepositoryModel . saveRepository ( repository ) ; } async function issueCommentEvent ( data ) { Logger . info ( 'issueCommentEvent' ) ; await simpleHubEvent ( data ) ; } async function createEvent ( data ) { Logger . info ( 'createEvent' ) ; await simpleHubEvent ( data ) ; } async function memberEvent ( data ) { Logger . info ( 'memberEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; await updateContributors ( repository ) ; await RepositoryModel . saveRepository ( repository ) ; } async function statusEvent ( data ) { Logger . info ( 'statusEvent' ) ; const repository = await RepositoryModel . getRepositoryById ( data . repository . id ) ; await updateContributors ( repository ) ; await RepositoryModel . saveRepository ( repository ) ; } async function updateContributors ( repository ) { const usersRef = await ( FirebaseAdmin . firestore ( ) . collection ( 'users' ) . where ( new FieldPath ( 'repositories' , 'uids' ) , 'array-contains' , repository . uid ) . get ( ) ) ; if ( ! usersRef . empty ) { for ( const element of usersRef . docs ) { const userData = element . data ( ) ; const githubToken = userData && userData . oauth ? userData . oauth . githubToken : null ; if ( githubToken ) { try { const response = await GitHubClient < GitHubContributorInput [ ] > ( `/repos/${ repository . fullName }/stats/contributors` , githubToken ) ; if ( Array . isArray ( response ) && response . length > 0 ) { repository . contributors = response . map ( ( contributor ) => GitHubContributorMapper . import ( contributor ) ) ; Logger . info ( 'Repository contributors updated' ) ; break ; } else { Logger . info ( 'Repository contributors empty' ) ; } } catch ( err ) { Logger . error ( err ) ; } } } } }